10

Consider the following program:

int main() {
    int* ptr = nullptr;
    return *ptr + 1;
}

(also on GodBolt)

How is it, that with "decent" warnings enabled (-Wall -Wextra), both popular compilers - clang++ 20.1.0, g++ 15.1 - fail to warn me about the null pointer dereferencing? Especially since they realize they don't need to bother adding 1?

Note: Same behavior if I compile it as C instead of C++.

30
  • 4
    Compiler warnings are generally based on static type analysis, not data flow. Commented Jun 11 at 20:19
  • 3
    @Barmar: Re “Compiler warnings are generally based on static type analysis, not data flow”: Not in 2025, and OP has demonstrated the compiler did in fact analyze the data flow and the specific value assigned to ptr. The code GCC generates contains ud2, showing that GCC recognized the behavior is undefined. Commented Jun 11 at 20:23
  • 13
    gcc warns with -Wnull-dereference Commented Jun 11 at 20:26
  • 2
    Incrementing a pointer outside the context of an address of an array is undefined behavior. C and C++ compilers are not required to identify undefined behavior. It is the responsibility of the programmer to avoid undefined behavior in C and C++. Commented Jun 12 at 2:17
  • 3
    I think your question boils down to basically why doesn't -Wall mean "all". This is for the authors of GCC to answer. Otherwise it's just opinions. Commented Jun 12 at 5:40

1 Answer 1

20

tl;dr: Because you didn't specifically ask for warnings about null dereferencing.

clang and GCC have a specific warning flag for this. Quoting the GCC man page:

-Wnull-dereference
    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.

I have not observed -fdelete-null-pointer-checks to have any effect on clang and GCC however, only by the optimization level and this flag. Here is how the effects seem to work right now (clang 20, GCC 15.1):

Compiler Optimization level -Wnull-dereference Other flags? Warning?
clang (none) On No
clang (none) Off No
GCC (none) On No
GCC (none) Off No
clang -O1 or higher On No (*)
clang -O1 or higher Off No (*)
GCC -O1 or higher On Yes
GCC -O1 or higher Off No
GCC (any) (any) -fanalyzer Yes

(*) If you fully-hand-inline everything:

int main() {
    return *(int*)(0) + 1;
}

clang will catch the null dereferencing (provided -Wnull-dereference)


What are we seeing here?

  1. A clang bug in the case of -O1 or higher and -Wnull-dereference. Thanks @n.m.canbeai for suggesting that. It is bug 113068, already reported last year.
  2. Both compilers are being very lazy in their static analysis even when you ask them for -Wnull-dereference. Is this a good idea? I would say no, or at least - you should be able to tell the compiler "even though I'm not asking for optimization, I do want you to statically analyze seriously".
  3. Both compilers don't believe that checking for null dereferences should be part of "all" warnings, nor even part of the "extra" warnings. IMNSHO that is quite bad, since a user is quite likely to assume that this check is part of one of those two.
  4. Both compilers avoid warning about null-dereferencing when not explicitly asked to do so, despite detecting - at some level - that it happens, and despite not being asked to suppress all warnings. This is not as bad, but still somewhat questionable.
  5. GCC's static analyzer, applicable from "within" the compiler, helps (at least in some cases).

Sign up to request clarification or add additional context in comments.

3 Comments

From the bug you linked, this comment by Aaron Ballman is fairly interesting: "In order to support this, we need to build a CFG". That is, Clang still has this odd architecture where it skips building a CFG (of its own), and instead goes directly from typed AST to LLVM IR. Contrast with rustc, which builds MIR (a CFG) and then lowers MIR to LLVM IR, which allows rustc to run control-flow diagnostics "for cheap", since the CFG is already built.
Did you try gcc's -fanalyzer? (C++ support is very preliminary, but the testcase is essentially C)
@MarcGlisse: I did and it detects the null-dereference. See edit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.