Menu

Preprocessor fails with simple macros

2018-12-10
2018-12-11
  • Jens Nissen

    Jens Nissen - 2018-12-10

    Evaluating typical static assertion patterns fails, either cppcheck misses invalid syntax or fails completely.
    See the attached example.
    Message is: "Analysis failed. If the code is valid then please report this failure."
    A gcc, mingw or clang compiler has no problems with the file.

     

    Last edit: Jens Nissen 2018-12-10
  • versat

    versat - 2018-12-11

    testCppCheck.c:

    #define NUM_ELEMENTS(arr) (sizeof (struct {int not_an_array:((void*)&(arr) == &((arr)[0]));}) * 0 + sizeof (arr) / sizeof (*(arr)))
    
    #define XX_STATIC_ASSERT2(cond,a,b) typedef char a##b[(cond) ? 1 : -1]
    #define XX_STATIC_ASSERT(cond,a,b) XX_STATIC_ASSERT2(cond,a,b)
    #define OS_STATIC_ASSERT(cond) XX_STATIC_ASSERT(cond,EXPR_,__LINE__)
    
    void bug_static()
    {
        static const char* const names[] = 
        {
            "P1",                   /* 0 */
            "P2"
        };
        OS_STATIC_ASSERT(2 == 2);  //!< No problem found - ok
    #ifdef CPPCHECK_ONLY
        OS_STATIC_ASSERT(2 == 3);  //!< No problem found - bug - should be reported
    #endif
        if (NUM_ELEMENTS(names) == 2) //!< No problem found - ok
        {
            return 0;
        }
        OS_STATIC_ASSERT(NUM_ELEMENTS(names) == 2); //!< Fails - bug - should neither report nor fail
    }
    
    // Included so that we can compile the stuff
    void main(int argc)
    {
        return 0;
    }
    

    gcc -E:

    void bug_static()
    {
     static const char* const names[] =
     {
      "P1",
      "P2"
     };
     typedef char EXPR_14[(2 == 2) ? 1 : -1];
    
     if ((sizeof (struct {int not_an_array:((void*)&(names) == &((names)[0]));}) * 0 + sizeof (names) / sizeof (*(names))) == 2)
     {
      return 0;
     }
     typedef char EXPR_22[((sizeof (struct {int not_an_array:((void*)&(names) == &((names)[0]));}) * 0 + sizeof (names) / sizeof (*(names))) == 2) ? 1 : -1];
    }
    
    void main(int argc)
    {
     return 0;
    }
    

    cppcheck -E (removed/added spaces for easy comparison with the gcc output):

    void bug_static()
    {
     static const char* const names[] =
     {
      "P1",
      "P2"
     };
     typedef char EXPR_5[(2 == 2) ? 1 : -1];
    
     if ((sizeof (struct {int not_an_array:((void*)&(names) == &((names)[0]));}) * 0 + sizeof (names) / sizeof (*(names))) == 2)
     {
      return 0;
     }
     typedef char EXPR_5[((sizeof (struct {int not_an_array:((void*)&(names) == &((names)[0]));}) * 0 + sizeof (names) / sizeof (*(names))) == 2) ? 1 : -1];
    }
    
    void main(int argc)
    {
     return 0;
    }
    

    The only difference of the gcc and Cppcheck preprocessor output is that Cppcheck (or better simplecpp) uses other line numbers (and two times the same line number!) for the EXPR_<line> arrays.
    And even if i use the preprocessed output of gcc i still get the message "Analysis failed. ..." from Cppcheck. So it looks not like an issue with simplecpp (except the thing with the line numbers).

     

    Last edit: versat 2018-12-13

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.