digitalmars.D - null pointer dereference detection in DMD
- Walter Bright (20/20) Jan 10 Consider:
- Richard (Rikki) Andrew Cattermole (30/33) Jan 10 Yeah you didn't turn the warning on.
- Richard (Rikki) Andrew Cattermole (25/25) Jan 10 For clang:
- Richard (Rikki) Andrew Cattermole (9/9) Jan 10 For MSVC:
- Iain Buclaw (13/21) Jan 11 [...snip...]
- Derek Fawcus (38/38) Jan 11 Interesting, I get a different error from GCC:
- Walter Bright (8/9) Jan 11 Thanks for pointing that out. That's one of the two problems with warnin...
- Iain Buclaw (13/16) Jan 12 Previous work on this.
- Walter Bright (1/1) Jan 13 Thank you!
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
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
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
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
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:[...snip...]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.flags: ``-Wnull-dereference -O``[...snip...]https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.htmlErgo, 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
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
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
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