Почему мой статический анализатор не смог найти потенциальное неинициализированное чтение? - PullRequest
0 голосов
/ 27 сентября 2018

Мне интересно, почему инструменты статического анализатора, которые я использую, не смогли обнаружить следующую простую ошибку (потенциально унифицированную переменную):

    S08 GPS_Nmea::handler(GPS_INF *pGps, U08 *pRcvd) {
      S08 sErr;
      U08 byte;
      U08 mask = 0;
      U08 stat_mask;

      while (Q08_GetLength(&gps_q)) {
        sErr = Q08_Read(&gps_q, &byte, 1);
        if (sErr != Q_OK)
          continue;
        if ((EPBEXSTN.RS_Settings.D == RS485_NMEA_OUT) ||
            (EPBEXSTN.RS_Settings2.D == RS485_NMEA_OUT) ||
            (EPBEXSTN.RS_Settings3.D == RS485_NMEA_OUT)) {
          if (ts.p_dev != 0)
            ts.p_dev->write(&byte, 1);
        }
        sErr = _gps_fsm(byte);
        if (sErr == TRUE) {
          sErr = _gps_parse(gps_buf, pGps, &stat_mask);
          gps_rx_state = GPS_ST_WAIT;

          if (stat_mask == STR_RMC)
            mask |= STR_RMC;
          if (stat_mask == STR_GGA)
            mask |= STR_GGA;
          mask |= STR_ANY;
        }
      }

      if (pRcvd != NULL)
        *pRcvd = mask;

      return RC_ERR_NONE;
    }

S08 GPS_Nmea::_gps_parse (char* pBuf, GPS_INF* pGps, U08* pRcvd)
{
    S08 sErr;

    if ((memcmp(pBuf, "$GPRMC", 6) == 0) ||
        (memcmp(pBuf, "$GLRMC", 6) == 0) ||
        (memcmp(pBuf, "$GNRMC", 6) == 0))
    {
        APP_PRINTF (GPS_TRACE, ("-I- gps: $xxRMC parse\r\n"));
        //APP_PRINTF (GPS_TRACE, ("-I- gps: string - %s\r\n", gps_buf));

        GpsTmp = *pGps;
        sErr = _gprmc_parse (pBuf, &GpsTmp);
        if (sErr == RC_ERR_NONE)
        {
            *pGps = GpsTmp;
            *pRcvd = STR_RMC;

            if (pGps->valid == FALSE)
                APP_PRINTF (GPS_WARNING, ("-W- gps_lib: gps data isn't valid\r\n"));
        }
        else
        {
            APP_PRINTF (GPS_ERROR, ("-E- gps_lib: _gprmc_parse() error\r\n"));
            clr_struct (pGps);
        }

        return sErr;
    }
    else if ((memcmp(pBuf, "$GPGGA", 6) == 0) ||
             (memcmp(pBuf, "$GLGGA", 6) == 0) ||
             (memcmp(pBuf, "$GNGGA", 6) == 0))
    {
        APP_PRINTF (GPS_TRACE, ("-I- gps: $xxGGA parse\r\n"));
        //APP_PRINTF (GPS_TRACE, ("-I- gps: string - %s\r\n", gps_buf));

        GpsTmp = *pGps;
        sErr = _gpgga_parse (pBuf, &GpsTmp);
        if (sErr == RC_ERR_NONE)
        {
            *pGps = GpsTmp;
            *pRcvd = STR_GGA;
        }
        else
        {
            APP_PRINTF (GPS_ERROR, ("-E- gps_lib: _gpgga_parse() error\r\n"));
            clr_struct (pGps);
        }

        return sErr;
    }
    else if ((memcmp(pBuf, "$GPGSV", 6) == 0) ||
             (memcmp(pBuf, "$GLGSV", 6) == 0) ||
             (memcmp(pBuf, "$GNGSV", 6) == 0) )
  {
    APP_PRINTF (GPS_TRACE, ("-I- gps: $xxGSV parse\r\n"));

        sErr = _gpgsv_parse (pBuf);
        if (sErr == RC_ERR_NONE)
        {
        }
        else
        {
            APP_PRINTF (GPS_ERROR, ("-E- gps_lib: _gpgga_parse() error\r\n"));
        }
        return sErr;
  }
    else if ((memcmp(pBuf, "$GPGSA", 6) == 0) ||
             (memcmp(pBuf, "$GLGSA", 6) == 0) ||
             (memcmp(pBuf, "$GNGSA", 6) == 0) )
  {
    APP_PRINTF (GPS_TRACE, ("-I- gps: $xxGSA parse\r\n"));
        GpsTmp = *pGps;
        sErr = _gpgsa_parse (pBuf, &GpsTmp);
        if (sErr == RC_ERR_NONE)
        {
            *pGps = GpsTmp;
            *pRcvd = STR_GSA;
        }
    else
        {
            APP_PRINTF (GPS_ERROR, ("-E- gps_lib: _gpgga_parse() error\r\n"));
        }
        return sErr;
  }
    else if ((memcmp(pBuf, "$GPZDA", 6) == 0) ||
             (memcmp(pBuf, "$GLZDA", 6) == 0) ||
             (memcmp(pBuf, "$GNZDA", 6) == 0) )
  {
    APP_PRINTF (GPS_TRACE, ("-I- gps: $xxZDA parse\r\n"));
        GpsTmp = *pGps;
        sErr = _gpzda_parse (pBuf);
        if (sErr == RC_ERR_NONE)
        {
            *pGps = GpsTmp;
            *pRcvd = STR_ZDA;
        }
    else
        {
            APP_PRINTF (GPS_ERROR, ("-E- gps_lib: _gpzda_parse() error\r\n"));
        }
        return sErr;
  }
    else if (memcmp(pBuf, "$PMTK705", 8) == 0) 
  {
    APP_PRINTF (GPS_TRACE, ("-I- gps: $PMTK705 parse\r\n"));
    int ver_len = strlen(pBuf+9) - 4;
    if (ver_len > sizeof(tsk_gps.gps_version)-1)
      ver_len = sizeof(tsk_gps.gps_version)-1;
    memcpy(tsk_gps.gps_version,pBuf+9,ver_len);
        return RC_ERR_NONE;
  }
    else if (memcmp(pBuf, "$PMTKSPF", 8) == 0) 
  {
    static U08 jamming_active_cnt = 0;
    static U08 jamming_prev_state = FALSE;
    APP_PRINTF (GPS_TRACE, ("-I- gps: $PMTKSPF parse\r\n"));
    tsk_gps.jamming_pmtk_to = 0;
    if (memcmp(pBuf, "$PMTKSPF,3", 10) == 0)
    { if (jamming_active_cnt < 60) jamming_active_cnt ++; }
    else
    { if (jamming_active_cnt != 0) jamming_active_cnt --; }
    if (jamming_active_cnt > 30)
    {
      if (bsp.m_DevInfo.jamming_gps)
      {
        tsk_gps.jamming_data = TRUE;
        if (jamming_prev_state == FALSE)
        {
          ev_bus.add(GLOB_EV_JAMMING_GPS);
        }
      }
      jamming_prev_state = TRUE;
    }
    else
      jamming_prev_state = FALSE;
        return RC_ERR_NONE;
  }
#if defined (MAKE_ERA)
    else if (memcmp(pBuf, "$PSTMGETALGOOK", 14) == 0)
  {
        if (memcmp(pBuf+15, "1,1", 3) == 0)
    {
            pGps->fde_status = 1;
        }
    else
        {
            pGps->fde_status = 0;
        }
        return sErr;
  }
#endif
    else
    {
        gps_buf[6] = 0;
        //APP_PRINTF (GPS_WARNING, ("-W- gps: undef string - %s\r\n", gps_buf));
    }

    return RC_ERR_DATA;
}

Объяснение ошибки: Переменная stat_mask унифицирована в функции handler() (строка44) может быть неизменным в вызываемой функции _gps_parse() (строка 59).Кажется очевидной ошибкой (для инструментов статического анализа), но ни один из инструментов, которые я использовал, не указал мне на это.

Редактировать 1. Добавлен полный исходный код: gpc_nmea.cpp Здесь вы можетесм. функцию

Используемый инструмент анализатора: PVS Studio

Редактировать 2. Вот упрощенная версия кода, содержащего эту ошибку:

include <stdio.h>

void func(int a, int *px) {
    if (a == 1) 
    {
        *px = 1;
    }
}

int main (void)
{    
    int x;
    func(2, &x);
    printf(x);
}

Может ли кто-нибудь предложить мне какой-либо инструмент анализа, который может указать мне, что переменная x может быть неинициализирована?Не могу поверить, что у человечества до сих пор нет такого решения.

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Да, в данный момент анализатор PVS-Studio не может обнаружить эту ошибку.Случай кажется очень простым, но на самом деле такой анализ довольно сложен.Мы постоянно совершенствуем межпроцедурный анализ и анализ потока данных.Мы надеемся, что со временем станет возможным обнаруживать и такие ошибки.

PS В таких случаях статические анализаторы обычно поддаются, поскольку они не могут учитывать все взаимосвязи и отслеживать изменение переменных.Динамические анализаторы кода хорошо выполняют поиск неинициализированных переменных.Попробуйте один из динамических анализаторов.

PPS, но просто не пытайтесь выбрать, что использовать: статический или динамический анализ.Некоторые ошибки могут быть в значительной степени обнаружены статическими анализаторами, другие - динамическими.Эти методологии прекрасно дополняют друг друга.Подробнее: Статический и динамический анализ кода .

0 голосов
/ 27 сентября 2018

Поскольку вы фактически пишете в *pRcvd внутри условия, статический анализатор может не иметь возможности легко определить, будет ли это условие когда-либо оцениваться как ложное.Особенно, если значение в условии происходит из связанной библиотеки.

Я мог бы представить, что статический анализатор может решить вообще не предупреждать - если он не уверен.Поскольку ложно-положительные предупреждения раздражают, и люди склонны игнорировать предупреждения, если их слишком много.

Хотя теоретически возможно обнаружить такую ​​ошибку, предполагая, что ее можно определить во время компиляции, она можетсделать это довольно сложно и, следовательно, может быть не реализовано в вашем статическом анализаторе.

...