Modo de verificação de limites de buffers implementado para a linguagem C baseado no Clang.

Engenheiros da Apple anunciaram que estão prontos para testar o modo "-fbounds-safety" para o compilador Clang, que oferece garantias de operação segura com buffers em código C. O modo está incluído no fork LLVM, suportado pela Apple para o projeto Swift. No futuro, está prevista uma transição gradual da funcionalidade "-fbounds-safety" para a base de código principal do LLVM/Clang.

Observa-se que o mecanismo de proteção proposto já está sendo amplamente utilizado em produtos da Apple, como o núcleo XNU, firmwares, bibliotecas de áudio e decodificadores de imagens. A ativação do modo "-fbounds-safety" reduz o desempenho dos aplicativos em média em 5% (variando de -1% a 29%), aumenta o tamanho do código em 9,1% (variando de -1,4% a 38%) e retarda a compilação em 11%.

O uso do modo "-fbounds-safety" para detectar automaticamente a violação de limites de memória associada a ponteiros exige a adição de anotações especiais no código e a inclusão do arquivo de cabeçalho "ptrcheck.h". A essência do método de proteção proposto está na anexação automática de verificações de conformidade com os limites permitidos, adicionadas com base em anotações manuais ou tamanhos conhecidos pelo compilador.

Diferente do uso de ponteiros ampliados (wide pointer) no código, que contém informações sobre o limite superior e inferior do buffer além do endereço, o uso do modo "-fbounds-safety" não altera a ABI (Interface Binária de Aplicação), não modifica o formato dos ponteiros exportados e não requer reestruturação imediata para todo o projeto. No modo "-fbounds-safety", ponteiros ampliados são aplicados apenas em regiões que não interferem na ABI, enquanto para ponteiros que afetam a ABI, são utilizados ponteiros normais com substituição de verificações baseadas em anotações com informações sobre os limites.

As anotações devem ser anexadas a ponteiros em campos de estruturas e parâmetros de funções que apontam para um array de objetos, assim como a variáveis globais com ponteiros. Para ponteiros em variáveis locais, anotações não precisam ser adicionadas, pois elas são automaticamente tratadas como ponteiros ampliados, já incluindo informações sobre os limites permitidos. Dicas sobre construções no código que requerem a adição de anotações são fornecidas pelo compilador ao ser executado com a flag "-fbounds-safety".

O modelo de proteção baseado em «-fbounds-safety» pode ser implementado gradualmente, arquivo por arquivo, sem interromper o desenvolvimento de todo o projeto. A adição da proteção ao projeto envolve a especificação de anotações em um arquivo de código específico, a remoção de avisos do compilador e a realização de testes do funcionamento do programa, após o que essas etapas são repetidas para o próximo arquivo. O código com as anotações adicionadas permanece compatível com o código C normal e com compiladores que não suportam «-fbounds-safety» (ao compilar com outros compiladores ou sem a flag «-fbounds-safety», simplesmente não serão adicionadas verificações adicionais de limites).

Durante a execução do programa, caso seja detectado um acesso fora dos limites permitidos, uma exceção é gerada e o programa encerra sua execução. Um encerramento inesperado também pode ocorrer ao especificar anotações incorretas, portanto, ao utilizar «-fbounds-safety» é necessário realizar testes adicionais do funcionamento do programa.

No exemplo abaixo, a anotação «__counted_by(n)» foi inserida no parâmetro «int *p», adicionando uma verificação adicional sobre os limites permitidos, que atua durante a execução. Se você tentar compilar o código em modo «-fbounds-safety» sem especificar essa anotação, o compilador emitirá um aviso sobre a falta de informações sobre os limites do array ao processar a expressão «p[i] = 0». #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // em modo «-fbounds-safety» o compilador adicionará automaticamente uma verificação semelhante ao código «if (i = n) trap();» }

Para variáveis locais com ponteiros, as verificações são acopladas automaticamente, por exemplo: void foo(int i){ char *buf = (char *)malloc(10); // para o ponteiro buf, serão salvas informações sobre os limites buf[i] = 0xff; // será automaticamente adicionada uma verificação «if (buf + i = buf + 10) trap();» }

Sempre que possível, o compilador realiza otimização e exclui a adição de código redundante, se o código já contiver as verificações necessárias. Por exemplo: for (size_t i = 0; i < count; ++i) { buf[i] = i; // a verificação "if (i = count) trap()» não será adicionada, pois já existe a condição «i < count" e i não pode ser menor que 0. }

Anotações principais:

  • «__counted_by(N)» — define o tamanho do buffer em elementos do tipo alvo.
  • «__sized_by(N)» — define o tamanho do buffer em bytes.
  • » __ended_by(P)» — define o limite superior do buffer.
  • «__null_terminated» — considera o caractere nulo como o final do buffer.
  • «__single» — vincula o ponteiro a um único objeto. Usado por padrão para ponteiros que afetam o ABI, a menos que a anotação seja explicitamente definida.
  • «__bidi_indexable» — ponteiro avançado com informações sobre os limites superior e inferior. Usado por padrão para ponteiros que não afetam o ABI.
  • «__indexable» — ponteiro avançado com informações sobre o limite superior.
  • «__unsafe_indexable» — ponteiro sem verificação de limites (para compatibilidade com código não seguro, por exemplo, para obter ponteiros de código externo).

Fonte: opennet.ru

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster