www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - null pointer dereference detection in DMD

reply Walter Bright <newshound2 digitalmars.com> writes:
Consider:
```
void main()
{
     int* p;
     *p = 3;
}
```
Compiling it and running it results in "Segmentation fault (core dumped)".

But compiling it with -O results in a compile time error:

```
Error: null dereference in function _Dmain
```

What's happening here? The optimizer does DFA (Data Flow Analysis) and can 
statically determine that `p` is null when deferenced.

(The message is a bit generic because the optimizer turns the source code into 
hamburger, and the cow is not easily reconstructed.)

Curiously, compiling it with `gcc -O3` does not detect it. ImportC doesn't 
detect it, either, a choice made because some C code uses such a construct as a 
way to drop into the debugger.
Jan 10
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 11/01/2025 2:43 PM, Walter Bright wrote:
 Curiously, compiling it with `gcc -O3` does not detect it. ImportC 
 doesn't detect it, either, a choice made because some C code uses such a 
 construct as a way to drop into the debugger.
Yeah you didn't turn the warning on. ```c int main() { int* ptr; *ptr = 3; return 0; } ``` flags: ``-Wnull-dereference -O`` ``` <source>: In function 'main': <source>:5:10: warning: null pointer dereference [-Wnull-dereference] 5 | *ptr = 3; | ~~~~~^~~ ASM generation compiler returned: 0 <source>: In function 'main': <source>:5:10: warning: null pointer dereference [-Wnull-dereference] 5 | *ptr = 3; | ~~~~~^~~ Execution build compiler returned: 0 Program returned: 139 Program terminated with signal: SIGSEGV ``` https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html "Warn if the compiler detects paths that trigger erroneous or undefined behavior due to dereferencing a null pointer. This option is only active when -fdelete-null-pointer-checks is active, which is enabled by optimizations in most targets. The precision of the warnings depends on the optimization options used."
Jan 10
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
For clang:

flags: ``-Wall --analyze``

```
<source>:5:10: warning: Dereference of null pointer (loaded from 
variable 'ptr') [core.NullDereference]
     5 |     *ptr = 3;
       |      ~~~ ^
1 warning generated.
ASM generation compiler returned: 0
clang: warning: -Wl,-rpath,./lib: 'linker' input unused 
[-Wunused-command-line-argument]
clang: warning: -Wl,-rpath,/opt/compiler-explorer/gcc-13.2.0/lib64: 
'linker' input unused [-Wunused-command-line-argument]
clang: warning: -Wl,-rpath,/opt/compiler-explorer/gcc-13.2.0/lib32: 
'linker' input unused [-Wunused-command-line-argument]
clang: warning: argument unused during compilation: '-L./lib' 
[-Wunused-command-line-argument]
<source>:5:10: warning: Dereference of null pointer (loaded from 
variable 'ptr') [core.NullDereference]
     5 |     *ptr = 3;
       |      ~~~ ^
1 warning generated.
Execution build compiler returned: 0
Program returned: 255
```
Jan 10
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
For MSVC:

flags: ``/analyze``

```
<source>(5) : warning C6011: Dereferencing NULL pointer 'ptr'. : Lines: 4, 5
ASM generation compiler returned: 0
example.c
<source>(5) : warning C6011: Dereferencing NULL pointer 'ptr'. : Lines: 4, 5
Execution build compiler returned: 0
```
Jan 10
prev sibling next sibling parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On Saturday, 11 January 2025 at 02:01:50 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 11/01/2025 2:43 PM, Walter Bright wrote:
 Curiously, compiling it with `gcc -O3` does not detect it. 
 ImportC doesn't detect it, either, a choice made because some 
 C code uses such a construct as a way to drop into the 
 debugger.
Yeah you didn't turn the warning on.
[...snip...]
 flags: ``-Wnull-dereference -O``
[...snip...]
 https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Ergo, gdc also warns about this with the same flags. ``` $ gdc nullptrdect.d -O -Wnull-dereference nullptrdect.d: In function ‘D main’: nullptrdect.d:3:10: warning: null pointer dereference [-Wnull-dereference] 3 | *ptr = 3; | ^ ```
Jan 11
prev sibling next sibling parent Derek Fawcus <dfawcus+dlang employees.org> writes:
Interesting, I get a different error from GCC:


```
$ gcc -g -O2 -std=c11 -Wall -Wextra -Wpedantic -Werror null.c
null.c:1:6: error: return type of ‘main’ is not ‘int’ 
[-Werror=main]
     1 | void main()
       |      ^~~~
null.c: In function ‘main’:
null.c:4:8: error: ‘p’ is used uninitialized 
[-Werror=uninitialized]
     4 |     *p = 3;
       |     ~~~^~~
cc1: all warnings being treated as errors
```

Which is more accurate, as there is no guarantee an uninitialised 
auto pointer will actually be NULL, rather than arbitrary garbage.

That is GCC 11.4.0, using GCC 12.3.0 adds:

```
null.c:3:10: note: ‘p’ was declared here
     3 |     int* p;
       |          ^
cc1: all warnings being treated as errors
```

After correcting the return type, and adding a return 0, clang 
14.0.0 gives me:

```
$ clang-14 -g -O2 -std=c11 -Wall -Wextra -Wpedantic -Werror null.c
null.c:4:6: error: variable 'p' is uninitialized when used here 
[-Werror,-Wuninitialized]
     *p = 3;
      ^
null.c:3:11: note: initialize the variable 'p' to silence this 
warning
     int* p;
           ^
            = 0
1 error generated.
```
Jan 11
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 1/10/2025 6:01 PM, Richard (Rikki) Andrew Cattermole wrote:
 Yeah you didn't turn the warning on.
Thanks for pointing that out. That's one of the two problems with warnings. The other problem is each C compiler has a different idea of warnings, and sometimes they are mutually contradictory. This makes porting code between compilers problematic with all warnings on, which led me (years ago) to give up on turning all warnings on. This led to my original concept of D as having no warnings. We should probably revisit our current set of warnings and see if they can be made errors.
Jan 11
parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
On Saturday, 11 January 2025 at 20:39:13 UTC, Walter Bright wrote:
 This led to my original concept of D as having no warnings. We 
 should probably revisit our current set of warnings and see if 
 they can be made errors.
Previous work on this. https://github.com/dlang/dmd/pull/15716 https://github.com/dlang/dmd/pull/15718 https://github.com/dlang/dmd/pull/15719 https://github.com/dlang/dmd/pull/15720 https://github.com/dlang/dmd/pull/15721 https://github.com/dlang/dmd/pull/16197 https://github.com/dlang/dmd/pull/16198 Unless new ones have been added, I don't think there are much left. And the majority that are, I'm not sure what alternate diagnostic they should be using. For example `#pragma pack(show)` or all DDoc warnings.
Jan 12
parent Walter Bright <newshound2 digitalmars.com> writes:
Thank you!
Jan 13