Por que o PVS-Studio usa análise de fluxo de dados: devido a um erro interessante na Biblioteca de importação de ativos abertos

PVS-Studio - Análise de Fluxo de Dados

A análise de fluxo de dados é parte integrante de qualquer analisador de código estático moderno. No entanto, do lado de fora, não está muito claro o que é e o que é mais importante - por que é necessário. Até agora, algumas pessoas associam a análise estática à busca por algo no código de acordo com um determinado padrão. Portanto, de vez em quando fazemos anotações nas quais demonstramos como esta ou aquela tecnologia, usada no analisador PVS-Studio, ajuda a revelar outro erro interessante. Hoje é apenas um artigo em que consideraremos um bug em uma das implementações do padrão de codificação de dados binários Base64.







Tudo começou com a verificação da versão mais recente da biblioteca Qt 6. Este foi um artigo clássico separado , onde descrevi 77 erros encontrados. Acontece que a princípio decidi folhear o relatório, ainda sem esconder os avisos relacionados a bibliotecas de terceiros. Em outras palavras, não desativei os avisos relacionados a \ src \ 3rdparty nas configurações. E aconteceu que imediatamente me deparei com um exemplo interessante de um erro na Biblioteca de importação de ativos aberta , sobre o qual decidi fazer esta pequena observação separada.







, , PVS-Studio, . . , , ", PVS-Studio ".







, , , Open Asset Import Library (assimp). : \src\3rdparty\assimp\src\code\FBX\FBXUtil.cpp.







std::string EncodeBase64(const char* data, size_t length)
{
    // calculate extra bytes needed to get a multiple of 3
    size_t extraBytes = 3 - length % 3;

    // number of base64 bytes
    size_t encodedBytes = 4 * (length + extraBytes) / 3;

    std::string encoded_string(encodedBytes, '=');

    // read blocks of 3 bytes
    for (size_t ib3 = 0; ib3 < length / 3; ib3++)
    {
        const size_t iByte = ib3 * 3;
        const size_t iEncodedByte = ib3 * 4;
        const char* currData = &data[iByte];

        EncodeByteBlock(currData, encoded_string, iEncodedByte);
    }

    // if size of data is not a multiple of 3,
    // also encode the final bytes (and add zeros where needed)
    if (extraBytes > 0)
    {
        char finalBytes[4] = { 0,0,0,0 };
        memcpy(&finalBytes[0], &data[length - length % 3], length % 3);

        const size_t iEncodedByte = encodedBytes - 4;
        EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);

        // add '=' at the end
        for (size_t i = 0; i < 4 * extraBytes / 3; i++)
            encoded_string[encodedBytes - i - 1] = '=';
    }
    return encoded_string;
}
      
      





, . , , Base64 :). :







  1. 31 ;
  2. ;
  3. legacy .


Ok, . Base64. 64 . - A-Z, a-z 0-9 (62 ) 2 , . 3 4 .







, , "=". . .







, . , . , , - . "- " : V547 [CWE-571] Expression 'extraBytes > 0' is always true. FBXUtil.cpp 224







, , extraBytes:







// calculate extra bytes needed to get a multiple of 3
size_t extraBytes = 3 - length % 3;
      
      





, , 3. 3. :







size_t extraBytes = length % 3;
      
      





, , , 5 , 5 % 3 = 2, 2 . 6 , , 6 % 3 = 0.







, , . :







size_t extraBytes = (3 - length % 3) % 3;
      
      





, . , :







size_t extraBytes = 3 - length % 3;
      
      





. length, [0..2]. PVS-Studio , . . . Value Range Analysis. .







:







size_t extraBytes = 3 - [0..2];
      
      





, extraBytes . : [1..3].







, . , , , :







if (extraBytes > 0)
      
      





, , , , , , , .







, , , . . , 6 . 8 . , .







// calculate extra bytes needed to get a multiple of 3
size_t extraBytes = 3 - length % 3; // 3-6%3 = 3

// number of base64 bytes
size_t encodedBytes = 4 * (length + extraBytes) / 3; // 4*(6+3)/3 = 12

std::string encoded_string(encodedBytes, '=');
      
      





, 12 , 8. – .







. , - , , Base64. , , , " , ".







PVS-Studio , . :). , . .







, : Andrey Karpov. Why PVS-Studio Uses Data Flow Analysis: Based on Gripping Error in Open Asset Import Library.








All Articles