3

Here's three files in which the first has a bug:

// main.cpp
#include <iostream>
#include "lib.h"


int main() {
    Deposit d; // Bug! Needs to be Deposit d = {};
    d.dollars = 3;
    // std::cout << reconfigure_params.version; // We do get an error here..
    run(&d);
    return 0;
}
// lib.cpp
#include <iostream>
#include "lib.h"

void run(Deposit* d) {
        std::cout << "Depositing " << d->dollars << " dollars and " << d->cents << " cents " << std::endl;
}
// lib.h
typedef struct _Deposit {
        int dollars;
        int cents;
} Deposit;


void run(Deposit* d);

How do I use GCC or some tool like clang-tidy or cppcheck to warn me about this bug?

Things I've tried:

$ g++ -c   -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused lib.cpp
$ g++   -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused lib.o main.cpp
=> No error
cppcheck --enable=all main.cpp
=> No error

I did notice when I ran cppcheck --enable all * I did get an error. I'm not sure how that works, but a more fair test would be to not have access to the lib source. That is, assume that lib is a compiled binary.

I hope this doesn't seem contrived. I ran into this precise issue with some NVIDIA code that took several days to track down. I'm hoping to prevent issues like this in the future.

Thanks!

theicfire
  • 2,719
  • 2
  • 26
  • 29
  • 1
    Unrelated to question: `_Deposit` is a reserved name because it starts with an underscore followed by an uppercase letter. It may therefore not be declared or defined as a macro by user code. – user17732522 May 05 '22 at 04:18
  • 1
    If you consider `Deposit d;` a bug that should be `Deposit d = {};`, then you probably should also consider the definition of `Deposit` a bug. It could have default member initializers to enforce the behavior of `Deposit d = {};`. But if the tool warned about all POD classes, it would probably be too noisy. – user17732522 May 05 '22 at 04:25
  • C++ don initialize the value of the vars: they have their previous memory position value, and thus, Which value do you think it'll have cents? You should declare Deposiit something like `typedef struct _Deposit { int dollars =0; int cents=0;} Deposit;` – Hiperion May 05 '22 at 04:32
  • One cool way you can prevent uninitialised nonsense is by using `auto`. If you write `auto d;`, the compiler will complain because it has no idea what `d` is meant to be. So you're forced to write `auto d = Deposit{};` which prevents you from ever leaving things uninitialised. – Tas May 05 '22 at 04:53
  • I agree there are multiple ways to fix this bug, but I want a tool that enforces this bug from happening, vs remembering to not write the subtle bug in the first place. Even if the class was properly created (which it's not in NVIDIA's library), I would still want to be given a warning for `Deposit d`. There's only exceptionally rare cases where I wouldn't want to zero-initialize a struct, in which case I would want to explicitly ignore the lint warning for that line. – theicfire May 05 '22 at 17:55

0 Answers0