Home > Blockchain >  What to do if an uninitialized pointer was used to write memory?
What to do if an uninitialized pointer was used to write memory?

Time:12-18

What can a programmer do to detect and/or rectify the problems created, when an uninitialized pointer was used to write memory in a system (in C ), for example when running this:

int main()
{
    int *ptr1;
    *ptr1 = 100;
}

CodePudding user response:

Any recent, decent compiler will warn on such code with the right flags. A general recommendation here is to always enable all warnings. Use -Wall on g /clang, and /W4 on MSVC (Visual C ).

For example:

uninit.cpp:

int main()
{
    int *ptr1;
    *ptr1 = 100;
}

g :

$ g   -Wall uninit.cpp
uninit.cpp: In function ‘int main()’:
uninit.cpp:4:11: warning: ‘ptr1’ is used uninitialized in this function [-Wuninitialized]
    4 |     *ptr1 = 100;
      |     ~~~~~~^~~~~

clang :

$ clang   -Wall uninit.cpp
uninit.cpp:4:6: warning: variable 'ptr1' is uninitialized when used here [-Wuninitialized]
    *ptr1 = 100;
     ^~~~
uninit.cpp:3:14: note: initialize the variable 'ptr1' to silence this warning
    int *ptr1;
             ^
              = nullptr
1 warning generated.

As you can see, the compiler even gives you a hint about the flag you need to use to specifically only turn on this single warning (-Wuninitialized).

Even with the warning turned on, an executable will be generated. If you want your compilation to fail on encountering warnings, add -Werror:

g   -Wall -Werror uninit.cpp
uninit.cpp: In function ‘int main()’:
uninit.cpp:4:11: error: ‘ptr1’ is used uninitialized in this function [-Werror=uninitialized]
    4 |     *ptr1 = 100;
      |     ~~~~~~^~~~~
cc1plus: all warnings being treated as errors

And again you see the compiler pointing out for you what flag you have to add to turn only this one specific warning into an error (-Werror=uninitialized).

For the more generalized treatment of potential invalid memory accesses, you can use an address sanitizer:

g   -fsanitize=address,undefined -g uninit.cpp

Output when running the program:

$ ./a.out
uninit.cpp:4:11: runtime error: store to null pointer of type 'int'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==191==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x562eab7b9255 bp 0x7ffc74f9a750 sp 0x7ffc74f9a740 T0)
==191==The signal is caused by a WRITE memory access.
==191==Hint: address points to the zero page.
    #0 0x562eab7b9254 in main /home/someuser/uninit.cpp:4
    #1 0x7ff1e1d6e0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6 0x270b2)
    #2 0x562eab7b912d in _start (/home/someuser/a.out 0x112d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/someuser/uninit.cpp:4 in main
==191==ABORTING

This builds in additional checks, so it comes with a performance cost; but it will warn you / stop the program during runtime when access problems resulting from more elaborate problems occur

As for rectifying such errors, it depends on the context on what the right solution is - there is no single answer that fits every use case, except the generic make sure that the pointer is initialized before it is used the first time. A good rule is to always initialize pointers directly after declaring them. This will of course only take care of such simple problems as shown above, and not of issues where a pointer is conditionally set to some invalid value. Use general bug fixing techniques to address these ;)

General recommendations would typically also include to avoid using raw pointers whenever possible.

CodePudding user response:

Both clang and GCC support sanitizers to catch such bugs. For example:

int main()
{
    volatile int* p; // volatile so it's not removed at compile time

    *p = 0;
}

Compile and run it:

$ g   main.cpp -O3 -fsanitize=undefined
$ ./a.out
main.cpp:5:8: runtime error: store to null pointer of type 'volatile int'

As you can see, there is a clear error message with the exact code location.

CodePudding user response:

What can a programmer do to ... rectify the problems created, when an uninitialized pointer was used

A programmer can change the program such that no indeterminate values are used in the program. You can fix the example program like this:

int main()
{
}

What can a programmer do to detect ... when an uninitialized pointer was used

  • A programmer can read the source, and deduce when an indeterminate value is used.

  • A programmer can read the warnings that their program may produce at compile time if the programmer is lucky. In case of the example program:

    warning: variable 'ptr1' is uninitialized when used here [-Wuninitialized]
    
  • A programmer can use undefined behaviour sanitisers that may detect the bug at runtime if the programmer is lucky. In case of the example program:

       /app/example.cpp:4:5: runtime error: store to address 0x7ffdda141688 with insufficient space for an object of type 'int'
      0x7ffdda141688: note: pointer points here
       00 00 00 00  f8 1e 14 da fd 7f 00 00  00 00 00 00 00 00 00 00  03 1f 14 da fd 7f 00 00  7a 1f 14 da
                  ^ 
      SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /app/example.cpp:4:5 in 
      AddressSanitizer:DEADLYSIGNAL
      =================================================================
      ==1==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x000000000000 sp 0x7ffdda141598 T0)
      ==1==Hint: pc points to the zero page.
      ==1==The signal is caused by a READ memory access.
      ==1==Hint: address points to the zero page.
          #0 0x0  (<unknown module>)
    
      AddressSanitizer can not provide additional info.
      SUMMARY: AddressSanitizer: SEGV (<unknown module>) 
      ==1==ABORTING
    
  • A programmer can automate the running of tests whenever the code is changed. Not only does this help make sure that the behaviour is implemented as desired, but it also gives the sanitisers an opportunity to find bugs.

CodePudding user response:

I don't see any harm in initialising the pointer to null. A lot of code out there checks for null before dereferencing a pointer.

int main()
{
    int *ptr1 = nullptr;
    if(ptr1 != nullptr)
        *ptr1 = 100;
}
  • Related