Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Move the null check ahead of the value’s first use, then handle absence according to the function’s contract. A check after a dereference cannot prevent a failure that has already occurred.

Why a check after a dereference is too late

A dereference is an operation that needs the referenced value to exist. In C and C++, that includes expressions such as *p and p->field. In Java, calling an instance method or accessing an instance field through null can throw NullPointerException. The operation happens before execution reaches a later check.

In C, dereferencing a null pointer is undefined behavior; it is not guaranteed to produce a clean, predictable crash. CERT C advises checking a potentially null pointer before using it: EXP34-C: Do not dereference null pointers.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
/* Wrong: *p is used before the check. */
use(*p);
if (p == NULL) {
    return ERROR;
}

/* Correct: decide what absence means first. */
if (p == NULL) {
    return ERROR;
}
use(*p);

The general rule is to establish that a value is usable before the first operation requiring it. The absent-value branch is part of the fix: moving the check alone does not determine what the program should do.

Repair the control flow

  1. Find the first operation that requires the value. Inspect the expression being evaluated, not just the line flagged by an analyzer. A compound expression may access a field or call a method before a later condition is reached.
  2. Trace where the value comes from. Check the function or API contract to learn whether absence is valid, signals a failed lookup, indicates invalid input, or violates an internal invariant.
  3. Choose the absent-value behavior. Return or propagate an error if the value is required; skip work if it is optional; use a fallback only if it has a valid, documented meaning.
  4. Check before use. Use the language’s ordinary conditional or guard-clause pattern. Keep the check close enough to the use that the control flow and value being checked are clear.
  5. Review all paths and re-run the relevant check. Confirm every path either establishes that the value is usable or handles absence before reaching the dereference. Run the project’s existing analyzer or a relevant regression test.

Use a guard clause when absence ends the operation

A guard clause keeps the normal path relatively flat when there is nothing useful to do without the value:

int *p = get_value();
if (p == NULL) {
    return ERROR;
}
consume(*p);

The return value shown is only an example. Select the result required by the function’s contract.

Use a conditional when only part of the work needs the value

If the rest of the function can continue without it, put only the dependent work inside the branch:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
if (optional_value != NULL) {
    use(*optional_value);
}
continue_other_work();

Whether skipping is correct depends on what the value represents; skipping a required operation may conceal a bug.

Choose the right behavior when the value is absent

  • Return or propagate an error when the value is required and its absence prevents the operation from succeeding.
  • Skip optional work when absence is explicitly allowed and the remaining operation is still valid.
  • Use a fallback only when the substitute is meaningful for the domain and documented. Returning an empty string, zero, or empty object merely to avoid a failure can turn a visible problem into incorrect output.
  • Treat absence as an invariant violation when the program’s own logic guarantees the value should exist. Report or handle that violation in line with the project’s error-handling policy rather than disguising it as an ordinary optional case.

Handle results from calls before using them

Store a potentially absent result once, check it, and then use that same result. Calling a lookup once for the test and again for the use can do duplicate work or produce a different result.

String name = findName();
if (name == null) {
    return; // Choose behavior that matches this method's contract.
}
System.out.println(name.length());

Some APIs return both a value and an error. Handle the error before using the value, and do not assume the value is usable merely because a call returned. MITRE’s CWE-476: NULL Pointer Dereference includes a Go example in which a response may be nil alongside an error, while a deferred dereference can occur before error handling.

Apply the rule in different languages

C and C++

For a raw pointer, test for null before dereferencing it. In C, a null pointer dereference is undefined behavior, so later source statements—including a check written afterward—cannot be relied on to recover. CERT C documents this rule in EXP34-C. C++ has multiple ways to represent ownership and optionality; which one is appropriate depends on the project’s design and C++ version. For a raw pointer that may be null, check before use.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Java

An instance-method call or instance-field access through a null reference can throw NullPointerException. Move the null-handling branch before that operation. Java’s Java SE 17 API documentation describes operations that can throw the exception. Optional can represent a result that may be absent, but it does not choose the correct behavior for that case; Oracle’s Optional article shows checking before using a contained object.

C#

Nullable reference types provide opt-in compile-time analysis intended to help identify possible null dereferences. The annotations do not change runtime reference types or enforce non-null values at runtime, so a warning is not a runtime safeguard. See Microsoft Learn’s nullable reference types documentation.

Rust

Rust represents possible absence with Option<T>, whose cases are Some and None. Match those cases or deliberately convert absence into an error or fallback. Calling unwrap on None panics, so it is not an automatic fix when absence is an expected condition. See The Rust Programming Language’s Option discussion and the Rust Option API.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Check nested values, repeated reads, and shared state

Nested dereferences

In a chain such as a->b->c or a.b.c, more than one reference may be nullable. Checking the first object does not establish that every nested field exists. Check each nullable link or use an explicit safe-navigation feature when the language provides one.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Repeated reads and expressions

If a value is obtained from a function or mutable property, save it when appropriate, check that saved value, and use it. A second call or read may have side effects or return something different from the value that was checked.

Concurrent or asynchronous mutation

A check may not protect a later read of shared mutable state if another thread or task can change the value in between. Use synchronization or establish stable ownership and lifetime across both the check and the use. MITRE discusses this concern in its CWE-476 guidance.

When a warning may not indicate a reachable failure

A static-analysis warning does not prove that every execution reaches a null dereference. Before changing code, verify that the warning concerns the same value at the check and the use, and examine whether the path is reachable. Then look for aliases, callbacks, mutation, or concurrent changes that could invalidate an earlier guarantee.

If an invariant truly guarantees the value is present, document and preserve that invariant in a way the team can verify. Suppress a warning only when the invariant is real and understood—not simply to make the warning disappear. A later null check may be stale defensive code or a sign of a maintenance regression; it cannot protect an operation that already used the value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Review the fix

  • The check is before the first operation that needs the value.
  • The null branch matches the function’s contract rather than using an arbitrary default.
  • The code checks and uses the same saved result where repeated calls or reads could differ.
  • Every nullable link in a nested expression is accounted for.
  • Shared mutable state remains stable across the check and use.
  • Relevant analyzer checks or regression tests pass, including the intended absent-value behavior.

A null dereference can create availability or security problems in some contexts, but the impact depends on the platform and circumstances; it is not automatically exploitable. MITRE describes the weakness and its context in CWE-476.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.