-1

I have a legacy code where there are like a zillion uninitialized

warning C4100: : unreferenced formal parameter

or potentially uninitialized:

warning C4701: potentially uninitialized local variable used

variables, which can cause undefined behavior later down the line. Is there any way to tell the compiler to set all the uninitialized variables to something more debuggable like NULL. Probably using either of options

  • preprocessing macros
  • compiler options
  • CMake options

For example, consider this dummy code:

#include <stdio.h>

int main() {

   int a;

   printf("%d\n",a);

   return 0;
}

I want to use either of the options above to set all cases like a to NULL or maybe in this case, 0 if NULL is not possible.

P.S. Here I'm using MSVC to catch the possible issues but in the end I want my solution to be cross platform and compiler agnostic. So compiler specific solutions (e.g., GCC, Clang...) are highly appreciated anyway.

Foad S. Farimani
  • 12,396
  • 15
  • 78
  • 193
  • 3
    No, there is not. – Jonathon Reinhart Mar 24 '20 at 23:48
  • 3
    And how would that make it more debuggable anyway? If the compiler is pointing out the errors to you then the best thing to do is to go in and fix them. Blindly setting values to some default value may cause more harm than good as it may hide problems until it inevitably has a runtime error at the least convenient time. – kaylum Mar 24 '20 at 23:51
  • 3
    No, there isn't a way to tell the compiler to do this. What I'd do [and have done similar in the past], is write a `perl/python` script that parses the compiler warnings and add an initializer to the declaration in the target source file (e.g. `char *ptr;` goes to `char *ptr = NULL;`). You could even make this interactive for some files and have the script ask a `y/n` question as to whether it should make the change. – Craig Estey Mar 24 '20 at 23:51
  • @CraigEstey would you be kind to share your scripts? In general what tools are out there to automatize this sort of painful stuff? – Foad S. Farimani Mar 24 '20 at 23:53
  • 1
    `tell the compiler` - which compiler are you talking to? – KamilCuk Mar 24 '20 at 23:53
  • @KamilCuk here I'm using MSVC to catch the possible issues. But in the end I hope my code to be cross-platform and compiler agnostic. – Foad S. Farimani Mar 24 '20 at 23:54
  • 1
    Cross platform is local variables have indeterminate value and if you want them to be initialized you should specify the initializer. As I was in the middle of researching an answer for gcc, you should modify your question, as the answer will be very compiler dependent. How is your question related to cmake? [This for gcc still holds](https://stackoverflow.com/questions/10526602/is-there-a-gcc-flag-to-initialise-local-variable-storage). No, this is not possible with gcc without a custom [plugin](https://lwn.net/Articles/727320/). – KamilCuk Mar 24 '20 at 23:56
  • @kaylum You are right. But for almost all of those zillion cases, a `0` initialization would suffice. Later I will add testing to the code base and I hope I can catch possible issues over there and edit the special cases then. – Foad S. Farimani Mar 24 '20 at 23:56
  • @KamilCuk would you be kind to provide the GCC specific solutions you have found? in the end, we can put everything together and have a compiler agnostic solution hopefully. – Foad S. Farimani Mar 24 '20 at 23:59
  • 1
    I have a framework [written in perl] for doing mass edits to source code [which has lots of safety checks] that is part of a much larger [too large] suite of tools I have. A single script isn't too difficult, just some regex to parse the error output and and then a rewrite of the target source. It only gets "interesting" if you have (e.g.) `char *ptr, *ptr2;` The script needs to have a "review" mode that just shows the changes without actually doing them. That way you "do no harm". I cloned your repo, did `cmake /home/src` but got `direct.h` No such file. I'm on linux, and this is MS? – Craig Estey Mar 25 '20 at 00:05
  • @CraigEstey would you please try the `develop` branch [here](https://github.com/Foadsf/ElmerGrid/tree/develop) – Foad S. Farimani Mar 25 '20 at 00:13
  • @CraigEstey for the moment I'm using MSVC and MSYS2-MinGWw64, but next I will move to Linux and macOS hopefully. – Foad S. Farimani Mar 25 '20 at 00:14
  • I commented out `#include ` but now `#include "metis.h"` reports the file is missing. – Craig Estey Mar 25 '20 at 00:35
  • @CraigEstey true. I have not set the instructions for Linux but it METIS is available on almost all Linux repositories according to the [Repology](https://repology.org/project/metis/versions). and if you clone the latest develop branch you don't have to comment anything thing out, hopefully :) – Foad S. Farimani Mar 25 '20 at 00:39
  • If a variable is set to a default value wouldn't it technically be initialized already? – October171 Mar 25 '20 at 01:24
  • 1
    If this code has a lot of variables that are used before being initialized then, in all likelihood, this is the least of your problems. These are very simple things to get right first time. The fact that the original authors did not get something so simple correct is likely a good indication that there are lots of bugs in this code. You should plan accordingly. Set the compiler to treat warnings as errors, and fix every single one. Plan to spend time on reviewing and fixing this software. – jarmod Mar 25 '20 at 02:59

1 Answers1

4

This is prefaced by my top comments.

I've cloned your develop repo.

Eventually, I was able to do a make -i. The output was about 500 lines [of errors].

So, there aren't enough errors to justify an automated script (i.e. by the time you get the script to production quality, you can do manual examination and fixup in less time).

And, some of the errors should be examined for logic errors, notably -Wmaybe-unitialized, which is what you were concerned with. Now might be a good time to determine if just changing: int foobar; into int foobar = 0; is okay. If so, that's what I'd do. (i.e.) If the code, based on the if hierarchy, never actually uses the value when it's uninitialized, adding int foobar = 0; just tells the compiler to STFU about a non-problem.

But, it may actually be a bug. If the code path the warning is complaining about is taken. Perhaps the code path hasn't shown up in practice, but, with different input data [in the future], the code is executed. This would be a [latent] bug.

At a minimum, just initializing with = 0; would change unpredictable random side effects into predictable side effects. If the function fails, it will now fail in a consistent/predictable way (vs. relying on the random value it gets in the [uninitialized] stack frame).

But, this would be a good time to desk check the code for [latent] bugs. You'll get more attaboys ;-)

A number of errors were -Wunused-parameter. Normally, I add -Wno-unused-parameter to CFLAGS if the code is known to be working. IMO, this really isn't even a bug [real, imaginary, or theoretical] most of the time--it's not an error to not use a parameter, just a warning for newbies writing new code. If you have a function signature that has an extra parameter that you have to keep for backwards compatibility, but the replacement function doesn't need it, you'll get a false positive here.

For -Wunused-but-set-variable, I'd remove the declaration and the assignment to it. Triage against int result = important_function_that_changes_globals();. There, keep the function call. Replace with: important_function_that_changes_globals();. Or, if you must [and, personally, I never do this]: (void) important_function_that_changes_globals();

But, there are others that indicate bugs (e.g.) -Wstringop-truncation which is indicative of [possible] buffer overflow.

The code base in the src subdirectory is [only] 30,000 lines. Again, with only about 500 lines of error messages.

Based on my experience, the errors could be triaged in 1-3 days [and one week max].

But, as jarmod pointed out, there may be more serious errors [that only show up with runtime debugging].

Craig Estey
  • 30,627
  • 4
  • 24
  • 48