Atualização do perfil vitalício no Visual Studio 2019 Preview 2

O Perfil Vitalício das Diretrizes Principais do C ++, que faz parte das Diretrizes Principais do C ++ , visa detectar problemas de vida útil, como indicadores e referências pendentes, no código C ++. Ele usa as informações de tipo já presentes na fonte, juntamente com alguns contratos simples entre funções para detectar defeitos no tempo de compilação com anotação mínima.





Original no blog

Estes são os contratos básicos que o perfil espera que o código siga:


  1. Não use um ponteiro potencialmente oscilante.
  2. Não passe um ponteiro potencialmente oscilante para outra função.
  3. Não retorne um ponteiro potencialmente danificado de nenhuma função.

Para obter mais informações sobre a história e os objetivos do perfil, consulte a publicação no blog de Herb Sutter sobre a versão 1.0 .


O que há de novo no Visual Studio 2019 Preview 2


Na Visualização 2, lançamos uma versão prévia do Lifetime Profile Checker, que implementa a versão publicada do Lifetime Profile . Esse verificador faz parte dos verificadores principais do C ++ no Visual Studio.


  • Suporte para iteradores, string_views e spans.
  • Melhor detecção de tipos personalizados de Proprietário e Ponteiro, o que permite que tipos personalizados se comportem como Contêineres, Ponteiros de Propriedade ou Ponteiros Não-Proprietários para participar da análise.
  • As regras padrão de reconhecimento de tipo para condições de pré e pós chamada de função ajudam a reduzir falsos positivos e melhorar a precisão.
  • Melhor suporte para tipos agregados.
  • Correção geral e melhorias de desempenho.
  • Alguma análise nullptr simples.

Ativando as regras do verificador de perfil vitalício


As regras do verificador não estão ativadas por padrão. Se você quiser experimentar as novas regras, precisará atualizar o conjunto de regras de análise de código selecionado para o seu projeto. Você pode selecionar as “Regras de tempo de vida útil da verificação principal do C ++” - que ativam apenas as regras do perfil de vida útil - ou pode modificar o conjunto de regras existente para ativar os avisos 26486 a 26489.


Captura de tela da página de propriedades Análise de código que mostra o conjunto de regras C ++ Core Check Lifetime Rules selecionado.

Captura de tela da página de propriedades Análise de código que mostra o conjunto de regras C ++ Core Check Lifetime Rules selecionado.


Os avisos aparecerão na Lista de erros quando a análise de código for executada (Analisar> Executar análise de código) ou, se você tiver a Análise de código em segundo plano ativada, os erros da vida útil aparecerão no editor com rabiscos verdes.


Captura de tela mostrando um aviso do Lifetime Profile Checker com um rabisco verde no código-fonte.

Captura de tela mostrando um aviso do Lifetime Profile Checker com um rabisco verde no código-fonte.


Exemplos


Ponteiro oscilante


O exemplo mais simples - usando um ponteiro pendente - é o melhor lugar para começar. Aqui, px aponta para x e, em seguida, x deixa o escopo, deixando o px dangling. Quando px é usado, um aviso é emitido.


 void simple_test() { int* px; { int x = 0; px = &x; } *px = 1; // error, dangling pointer to 'x' } 

Ponteiro de saída oscilante


Retornar ponteiros pendentes também não é permitido. Nesse caso, presume-se que o parâmetro ppx seja um parâmetro de saída. Nesse caso, ele deve apontar para x que fica fora do escopo no final da função. Isso deixa *ppx pendente.


 void out_parameter(int x, int** ppx) // *ppx points to 'x' which is invalid { *ppx = &x; } 

Exibição de string pendente


Os dois últimos exemplos foram óbvios, mas instâncias temporárias podem introduzir erros sutis. Você pode encontrar o bug no código a seguir?


 std::string get_string(); void dangling_string_view() { std::string_view sv = get_string(); auto c = sv.at(0); } 

Nesse caso, a exibição de string sv é construída com a instância de string temporária retornada de get_string() . A sequência temporária é então destruída, o que deixa a exibição de sequência fazendo referência a um objeto inválido.


Iterador dangling


Outro problema de vida útil difícil de detectar ocorre ao usar um iterador inválido em um contêiner. No caso abaixo, a chamada para push_back pode fazer com que o vetor realoque seu armazenamento subjacente, o que invalida o iterador.


 void dangling_iterator() { std::vector<int> v = { 1, 2, 3 }; auto it = v.begin(); *it = 0; // ok, iterator is valid v.push_back(4); *it = 0; // error, using an invalid iterator } 

Uma coisa a ser observada nesse exemplo é que não há tratamento especial para 'std :: vector :: push_back'. Esse comportamento cai fora das regras de perfil padrão. Uma regra classifica os contêineres como um 'Proprietário'. Em seguida, quando um método não-const é chamado no Proprietário, sua memória pertencente é considerada inválida e os iteradores que apontam para a memória pertencente também são considerados inválidos.


Proprietário modificado


O perfil é prescritivo em suas orientações. Ele espera que seu código use o sistema de tipos idiomamente ao definir parâmetros de função. Neste próximo exemplo, std::unique_ptr , um tipo 'Proprietário', é passado para outra função por referência não const. De acordo com as regras do perfil, presume-se que os proprietários passados ​​por referência não const sejam modificados pelo chamado.


 void use_unique_ptr(std::unique_ptr<int>& upRef); void assumes_modification() { auto unique = std::make_unique<int>(0); // Line A auto ptr = unique.get(); *ptr = 10; // ok, ptr is valid use_unique_ptr(unique); *ptr = 10; // error, dangling pointer to the memory held by 'unique' at Line A } 

Neste exemplo, obtemos um ponteiro bruto, ptr , para a memória pertencente a unique . Então unique é passado para a função use_unique_ptr por referência não const. Como esse é um uso não constante de unique onde a função pode fazer qualquer coisa, a análise assume que unique 'é invalidado de alguma forma (por exemplo, unique_ptr :: reset), o que causaria ptr no ptr .


Mais exemplos


Existem muitos outros casos que a análise pode detectar. Experimente no Visual Studio em seu próprio código e veja o que você encontra. Verifique também o blog de Herb para obter mais exemplos e, se você estiver curioso, leia o artigo do Lifetime Profile.


Problemas conhecidos


A implementação atual não suporta totalmente a análise, conforme descrito no documento do Perfil da vida útil. Aqui estão as categorias amplas que não são implementadas nesta versão.


  • Anotações - O documento apresenta anotações (ou seja, [[gsl::lifetime-const]] ) que não são suportadas. Na prática, isso significa que, se as regras de análise padrão não estiverem funcionando para o seu código, não há muito o que fazer além de suprimir falsos positivos.
  • Exceções - Os caminhos de manipulação de exceção, incluindo o conteúdo dos blocos de catch , não são atualmente analisados.
  • Regras padrão para tipos de STL - Em vez de uma anotação de lifetime-const , o documento recomenda que, para as raras funções de membros de contêineres de STL, nas quais desejamos substituir os padrões, os tratemos como se fossem anotados. Por exemplo, uma sobrecarga de std::vector::at não é const porque pode retornar uma referência que não seja const - no entanto, sabemos que chamá-lo é lifetime-const porque não invalida a memória do vetor. Não concluímos o trabalho para fazer esta anotação implícita de todos os tipos de contêineres STL.
  • Capturas Lambda - Se uma variável de pilha for capturada por referência em uma lambda, atualmente não detectamos se a lambda sai do escopo da variável capturada.

     auto lambda_test() { int x; auto captures_x = [&x] { return x; }; return captures_x; // returns a dangling reference to 'x' } 

Encerrar


Experimente o Verificador de perfil vitalício no Visual Studio 2019 Preview 2. Esperamos que ele ajude a identificar problemas de vida útil em seus projetos. Se você encontrar falsos positivos ou negativos, relate-os para que possamos priorizar os cenários que são importantes para você. Se você tiver sugestões ou problemas com essa verificação - ou qualquer recurso do Visual Studio - relate um problema ou publique na comunidade de desenvolvedores e informe-nos. Também estamos no Twitter em @VisualC .

Source: https://habr.com/ru/post/pt437660/


All Articles