Menu ▾ ▴

uninitMemberVarNoCtor flag members that cannot take a default member initializer

Long Huang
6 days ago
4 days ago
  • Long Huang

    Long Huang - 6 days ago

    uninitMemberVarNoCtor asks for a default member initializer on members of a constructor-less aggregate. Two kinds of member cannot take one:

    1. Bit-fields under --std=c++14/c++17: default member initializers
      for bit-fields only became valid in C++20. Cppcheck warns even with
      --std=c++14, so the suggested fix does not compile.
    2. Flexible array members (char Data[];, GNU/C99 extension common in
      wire/IPC headers): they have no size, so an initializer is impossible in
      any standard.

    A user-written constructor is not a practical alternative for (1) because it removes aggregate initialization, which these wire-layout structs rely on.

    Reproduction 1: bit-fields with --std=c++14

    bitfield.cpp:

    #include <cstdint>
    struct Wire
    {
       std::uint8_t Cmd = 1;
       std::uint8_t Mode : 4;
       std::uint8_t Reserved : 4;
    };
    Wire Make() { return Wire{2, 3, 0xF}; }
    int main() { return Make().Mode; }
    
    cppcheck --enable=style --std=c++14 --template=gcc --quiet bitfield.cpp
    

    Actual:

    bitfield.cpp:5:17: warning: Member variable 'Wire::Mode' has no initializer. [uninitMemberVarNoCtor]
    bitfield.cpp:6:17: warning: Member variable 'Wire::Reserved' has no initializer. [uninitMemberVarNoCtor]
    

    The suggested fix is rejected by the compiler in C++14:

    struct W { unsigned char M : 4 = 0; };
    
    $ g++ -std=c++14 -pedantic-errors -fsyntax-only bfinit.cpp
    bfinit.cpp:1:34: error: lvalue required as left operand of assignment
    

    Expected:

    No uninitMemberVarNoCtor for bit-fields when --std is older than
    C++20 (or at least a message that does not recommend an ill-formed fix).

    Reproduction 2: flexible array member

    flex.cpp:

    #include <cstdlib>
    #include <cstring>
    struct Payload
    {
       int Size = 0;
       char Data[];
    };
    int main()
    {
       Payload* p = static_cast<Payload*>(std::malloc(sizeof(Payload) + 4));
       if(p == nullptr)
       {
          return 1;
       }
       p->Size = 4;
       std::memcpy(p->Data, "abc", 4);
       const int r = p->Data[0] == 'a' ? 0 : 1;
       std::free(p);
       return r;
    }
    
    cppcheck --enable=style --std=c++14 --template=gcc --quiet flex.cpp
    g++ -std=gnu++14 -Wall -Wextra -o flex flex.cpp && ./flex   # exit 0
    

    Actual:

    flex.cpp:6:9: warning: Member variable 'Payload::Data' has no initializer. [uninitMemberVarNoCtor]
    

    Expected:

    No warning, a flexible array member has no storage in the struct itself and cannot have an initializer.

    Version

    Cppcheck 2.22.0 (Linux)

     
  • CHR

    CHR - 4 days ago

    Thanks for reporting, ticket is here: https://trac.cppcheck.net/ticket/15177

     

Log in to post a comment.