Programs must not catch java.lang.NullPointerException. A NullPointerException exception thrown at runtime indicates the existence of an underlying null pointer dereference that must be fixed in the application code (see EXP01-J. Do not use a null in a case where an object is required for more information). Handling the underlying null pointer dereference by catching the NullPointerException rather than fixing the underlying problem is inappropriate for several reasons. First, catching NullPointerException adds significantly more performance overhead than simply adding the necessary null checks [Bloch 2008]. Second, when multiple expressions in a try block are capable of throwing a NullPointerException, it is difficult or impossible to determine which expression is responsible for the exception because the NullPointerException catch block handles any NullPointerException thrown from any location in the try block. Third, programs rarely remain in an expected and usable state after a NullPointerException has been thrown. Attempts to continue execution after first catching and logging (or worse, suppressing) the exception rarely succeed.

Likewise, programs must not catch RuntimeException, Exception, or Throwable. Few, if any, methods are capable of handling all possible runtime exceptions. When a method catches RuntimeException, it may receive exceptions unanticipated by the designer, including NullPointerException and ArrayIndexOutOfBoundsException. Many catch clauses simply log or ignore the enclosed exceptional condition and attempt to resume normal execution; this practice often violates ERR00-J. Do not suppress or ignore checked exceptions. Runtime exceptions often indicate bugs in the program that should be fixed by the developer and often cause control flow vulnerabilities.

Noncompliant Code Example (NullPointerException)

This noncompliant code example defines an isName() method that takes a String argument and returns true if the given string is a valid name. A valid name is defined as two capitalized words separated by one or more spaces. Rather than checking to see whether the given string is null, the method catches NullPointerException and returns false.

boolean isName(String s) {
  try {
    String names[] = s.split(" ");

    if (names.length != 2) {
      return false;
    }
    return (isCapitalized(names[0]) && isCapitalized(names[1]));
  } catch (NullPointerException e) {
    return false;
  }
}

Compliant Solution

This compliant solution explicitly checks the String argument for null rather than catching NullPointerException:

boolean isName(String s) {
  if (s == null) {
    return false;
  }
  String names[] = s.split(" ");
  if (names.length != 2) {
    return false;
  }
  return (isCapitalized(names[0]) && isCapitalized(names[1]));
}

Compliant Solution

This compliant solution omits an explicit check for a null reference and permits a NullPointerException to be thrown:

boolean isName(String s) /* Throws NullPointerException */ {
  String names[] = s.split(" ");
  if (names.length != 2) {
    return false;
  }
  return (isCapitalized(names[0]) && isCapitalized(names[1]));
}

Omitting the null check means that the program fails more quickly than if the program had returned false and lets an invoking method discover the null value. A method that throws a NullPointerException without a null check must provide a precondition that the argument being passed to it is not null.

Noncompliant Code Example (Null Object Pattern)

This noncompliant code example is derived from the logging service Null Object design pattern described by Henney [Henney 2003]. The logging service is composed of two classes: one that prints the triggering activity's details to a disk file using the FileLog class and another that prints to the console using the ConsoleLog class. An interface, Log, defines a write() method that is implemented by the respective log classes. Method selection occurs polymorphically at runtime. The logging infrastructure is subsequently used by a Service class.

public interface Log {
  void write(String messageToLog);
}

public class FileLog implements Log {
  private final FileWriter out;

  FileLog(String logFileName) throws IOException {
    out = new FileWriter(logFileName, true);
  }

  public void write(String messageToLog) {
    // Write message to file
  }
}

public class ConsoleLog implements Log {
  public void write(String messageToLog) {
    System.out.println(messageToLog); // Write message to console
  }
}

class Service {
  private Log log;

  Service() {
    this.log = null; // No logger
  }

  Service(Log log) {
    this.log = log; // Set the specified logger
  }

  public void handle() {
    try {
      log.write("Request received and handled");
    } catch (NullPointerException npe) {
      // Ignore
    }
  }

  public static void main(String[] args) throws IOException {
    Service s = new Service(new FileLog("logfile.log"));
    s.handle();

    s = new Service(new ConsoleLog());
    s.handle();
  }
}

Each Service object must support the possibility that a Log object may be null because clients may choose not to perform logging. This noncompliant code example eliminates null checks by using a try-catch block that ignores NullPointerException.

This design choice suppresses genuine occurrences of NullPointerException in violation of ERR00-J. Do not suppress or ignore checked exceptions. It also violates the design principle that exceptions should be used only for exceptional conditions because ignoring a null Log object is part of the ordinary operation of a server.

Compliant Solution (Null Object Pattern)

The Null Object design pattern provides an alternative to the use of explicit null checks in code. It reduces the need for explicit null checks through the use of an explicit, safe null object rather than a null reference.

This compliant solution modifies the no-argument constructor of class Service to use the do-nothing behavior provided by an additional class, Log.NULL; it leaves the other classes unchanged.

public interface Log {

  public static final Log NULL = new Log() {
    public void write(String messageToLog) {
      // Do nothing
    }
  };

  void write(String messageToLog);
}

class Service {
  private final Log log;

  Service(){
    this.log = Log.NULL;
  }

  // ...
}

Declaring the log reference final ensures that its value is assigned during initialization.

An acceptable alternative implementation uses accessor methods to control all interaction with the reference to the current log. The accessor method to set a log ensures use of the null object in place of a null reference. The accessor method to get a log ensures that any retrieved instance is either an actual logger or a null object (but never a null reference). Instances of the null object are immutable and are inherently thread-safe.

Some system designs require returning a value from a method rather than implementing do-nothing behavior. One acceptable approach is use of an exceptional value object that throws an exception before the method returns [Cunningham 1995]. This approach can be a useful alternative to returning null.

In distributed environments, the null object must be passed by copy to ensure that remote systems avoid the overhead of a remote call argument evaluation on every access to the null object. Null object code for distributed environments must also implement the Serializable interface.

Code that uses this pattern must be clearly documented to ensure that security-critical messages are never discarded because the pattern has been misapplied.

Noncompliant Code Example (Division)

This noncompliant code example assumes that the original version of the division() method was declared to throw only ArithmeticException. However, the caller catches the more general Exception type to report arithmetic problems rather than catching the specific exception ArithmeticException type. This practice is risky because future changes to the method signature could add more exceptions to the list of potential exceptions the caller must handle. In this example, a revision of the division() method can throw IOException in addition to ArithmeticException. However, the compiler will not diagnose the lack of a corresponding handler because the invoking method already catches IOException as a result of catching Exception. Consequently, the recovery process might be inappropriate for the specific exception type that is thrown. Furthermore, the developer has failed to anticipate that catching Exception also catches unchecked exceptions.

public class DivideException {
  public static void division(int totalSum, int totalNumber)
    throws ArithmeticException, IOException  {
    int average  = totalSum / totalNumber;
    // Additional operations that may throw IOException...
    System.out.println("Average: " + average);
  }
  public static void main(String[] args) {
    try {
      division(200, 5);
      division(200, 0); // Divide by zero
    } catch (Exception e) {
      System.out.println("Divide by zero exception : " 
                         + e.getMessage());
    }
  }
}

Noncompliant Code Example

This noncompliant code example attempts to solve the problem by specifically catching ArithmeticException. However, it continues to catch Exception and consequently catches both unanticipated checked exceptions and unanticipated runtime exceptions.

try {
  division(200, 5);
  division(200, 0); // Divide by zero
} catch (ArithmeticException ae) {
  throw new DivideByZeroException();
} catch (Exception e) {
  System.out.println("Exception occurred :" + e.getMessage());
}

Note that DivideByZeroException is a custom exception type that extends Exception.

Compliant Solution

This compliant solution catches only the specific anticipated exceptions (ArithmeticException and IOException). All other exceptions are permitted to propagate up the call stack.

import java.io.IOException;

public class DivideException {
  public static void main(String[] args) {
    try {
      division(200, 5);
      division(200, 0); // Divide by zero
    } catch (ArithmeticException ae) {
      // DivideByZeroException extends Exception so is checked
      throw new DivideByZeroException();  
    } catch (IOException ex) {
      ExceptionReporter.report(ex);
    }
  }

  public static void division(int totalSum, int totalNumber)
                              throws ArithmeticException, IOException  {
    int average  = totalSum / totalNumber;
    // Additional operations that may throw IOException...
    System.out.println("Average: "+ average);
  }
}

The ExceptionReporter class is documented in ERR00-J. Do not suppress or ignore checked exceptions.

Compliant Solution (Java SE 7)

Java SE 7 allows a single catch block to catch multiple exceptions of different types, which prevents redundant code. This compliant solution catches the specific anticipated exceptions (ArithmeticException and IOException) and handles them with one catch clause. All other exceptions are permitted to propagate to the next catch clause of a try statement on the stack.

import java.io.IOException;

public class DivideException {
  public static void main(String[] args) {
    try {
      division(200, 5);
      division(200, 0); // Divide by zero
    } catch (ArithmeticException | IOException ex) {
      ExceptionReporter.report(ex);
    }
  }

  public static void division(int totalSum, int totalNumber)
                              throws ArithmeticException, IOException  {
    int average  = totalSum / totalNumber;
    // Additional operations that may throw IOException...
    System.out.println("Average: "+ average);
  }
}

Exceptions

ERR08-J-EX0: A catch block may catch all exceptions to process them before rethrowing them (filtering sensitive information from exceptions before the call stack leaves a trust boundary, for example). Refer to ERR01-J. Do not allow exceptions to expose sensitive information and weaknesses CWE 7 and CWE 388 for more information. In such cases, a catch block should catch Throwable rather than Exception or RuntimeException.

This code sample catches all exceptions and wraps them in a custom DoSomethingException before rethrowing them:

class DoSomethingException extends Exception {
  public DoSomethingException(Throwable cause) {
    super(cause);
  }

  // Other methods

};

private void doSomething() throws DoSomethingException {
  try {
    // Code that might throw an Exception
  } catch (Throwable t) {
    throw new DoSomethingException(t);
  }
}

Exception wrapping is a common technique to safely handle unknown exceptions. For another example, see ERR06-J. Do not throw undeclared checked exceptions.

ERR08-J-EX1: Task processing threads such as worker threads in a thread pool or the Swing event dispatch thread are permitted to catch RuntimeException when they call untrusted code through an abstraction such as the Runnable interface [Goetz 2006, p. 161].

ERR08-J-EX2: Systems that require substantial fault tolerance or graceful degradation are permitted to catch and log general exceptions such as Throwable at appropriate levels of abstraction. For example:

  • A real-time control system that catches and logs all exceptions at the outermost layer, followed by warm-starting the system so that real-time control can continue. Such approaches are clearly justified when program termination would have safety-critical or mission-critical consequences.
  • A system that catches all exceptions that propagate out of each major subsystem, logs the exceptions for later debugging, and subsequently shuts down the failing subsystem (perhaps replacing it with a much simpler, limited-functionality version) while continuing other services.

Risk Assessment

Catching NullPointerException may mask an underlying null dereference, degrade application performance, and result in code that is hard to understand and maintain. Likewise, catching RuntimeException, Exception, or Throwable may unintentionally trap other exception types and prevent them from being handled properly.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR08-J

Medium

Likely

Medium

P12

L1

Automated Detection

ToolVersionCheckerDescription
CodeSonar
8.1p0

JAVA.STRUCT.EXCP.GEH
JAVA.STRUCT.EXCP.INAPP

Generic Exception Handler (Java)
Inappropriate Exception Handler (Java)

Parasoft Jtest
2023.1
CERT.ERR08.NCNPEDo not catch 'NullPointerException'
SonarQube
9.9

S1181

S1696

Throwable and Error should not be caught

"NullPointerException" should not be caught

SpotBugs

4.6.0

DCN_NULLPOINTER_EXCEPTIONImplemented (since 4.5.0)



24 Comments

  1. I came across this CWE entry which uses a Java example and says precisely -

    Summary

    The default error page of a web application should not display sensitive information about the software system.

    Extended Description

    A Web application must define a default error page for 4xx errors (e.g. 404), 5xx (e.g. 500) errors and catch java.lang.Throwable exceptions to prevent attackers from mining information from the application container's built-in error response.

    In the snippet below, an unchecked runtime exception thrown from within the try block may cause the container to display its default error page (which may contain a full stack trace, among other things).

    Public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
    ...
    } catch (ApplicationSpecificException ase) {
    logger.error("Caught: " + ase.toString());
    }
    }
    

    By catching Throwable they address one problem but violate this rule.
    We could add an exception to the rule for J2EE because we really do not want to leak sensitive information by not providing a "default" error/exception reporter.

    1. Added an exception as requested.

      BTW Why is EXC06-J. Do not allow exceptions to transmit sensitive information a recommendation and not a rule? It has all the hallmarks of a solid rule to me.

      1. Thanks Dave. Regarding EXC01-J, the kind of (sensitive) information revealed through exceptions by itself does not always cause a vulnerability. That's why it's a recommendation. If it becomes a rule then there would be questions on what exactly constitutes "sensitive information". Unless that whole gap of determining what all "sensitive" includes is filled (which would be a good exercise actually), we could keep it the way it is. Do let me know if you have other inputs/ideas regarding its current classification.

        1. What information is considered 'sensitive' is defined by your security policy. For instance, if the user already has access to the file system, then information such as file system structre is not 'sensitive', and exceptions like FileNotFoundException require no filtering.

          I still say that EXC01-J should be a rule not a rec, as sensitive info disclosure is a security vulnerability by definition. Let the policymakers decide what constitutes 'sensitive'...that argument is really irrelevant to the validity of EXC01-J.

          Further discussion about the validity of EXC01-J should go there.

  2. I think this should pass according to this rec (an exception to the rule):

    try {
      throw new IllegalArgumentException();
    }catch(IllegalArgumentException iae) { System.out.println("caught iae"); } // specific
     catch(RuntimeException re) { System.out.println("caught some other, fault tolerant"); }
    

    The intro might need to reflect that. The second NCE/CS seems to be compliant. Similarly the EXC08-J. Try to gracefully recover from system errors could catch StackOverflowError and then Throwable.

    1. I don't see any context, but this looks like it falls under EXC32-J-EX1.

      1. It seems it would actually violate the rule. This rule tells you to catch specific exceptions but not a generic type like RuntimeException, even if its catch block occurs after the specific exception is caught. Right?

        1. Yes, and the exception (EXC32-J-EX1) says that catching RuntimeException is okay at the 'top level' of your code.

          The reason this rule is valid is the danger of casting too wide a net and catching & handling exceptions you aren't aware of.

          Bottom line, this code does violate the rule unless it is part of a top-level routine to protect the user from 'unknown' exceptions. Then it is protected by EXC32-J-EX1.

          1. Added an NCE below the second one, just to avoid confusion.

  3. The 1st CE catches NullPointerException, so it violates the new EXC34-J rule. I suggest changing the CE to:

    boolean isCapitalized(String s) {
      if (s == null) {
        return false;
      }
      if (s.equals("")) {
        return true;
      }
      String first = s.substring( 0, 1);
      String rest = s.substring( 1);
      return (first.equals (first.toUpperCase()) &&
    	  rest.equals (rest.toLowerCase()));
    }
    

    This code now handles s=null, s="", and s with a length of 1.

    In the 2nd CE, the none of the expressions in the divide() method throw IOException, which makes the method declaration a bit confusing. Maybe an comment alluding to some doing some other things that could cause IOException to be thrown would be worthwhile.

    1. If the first CS is changed, then it will become harder to explain the point of this guideline i.e. not to cast too wide a net. Let's just say that this code falls under the exception to EXC34-J and is consequently, valid.

      For the second CS, a comment can be added as you pointed out. Thanks.

      1. For the 1st NCCE/CE pair it may be better to show an example that does something with an array and initially catches RunTimeException in lieu of checking to see if the array index is in bounds. This casts too wide a net, so the CE would catch ArrayIndexOutOfBoundsException instead. This would not violate any secure coding rules.

        1. Why isn't catching ArrayIndexOutOfBoundsException a bad idea if catching NPException is? It might be unusual to check if an illegal array access is made (as opposed to checking for null) but that doesn't mean it is an exemplar. A good question to ask is - why does jdk source code catch unchecked exceptions?

  4. Need an exception to catch generalized exceptions if working with a library that throws generalized exceptions. Even though that is a violation of EXC13-J.

    1. Exception added. Also added an exception to allow fault-tolerance/graceful degradation when appropriate. Do we now have a reasonable set of exceptions listed?

  5. If "any class that catches RuntimeException also violates ERR15-J. Do not catch NullPointerException" why do we need ERR15-J?

  6. This is one of the compliant examples:

    boolean isName(String s) /* throws NullPointerException */ {
      String names[] = s.split(" ");
      if (names.length != 2) {
        return false;
      }
      return (isCapitalized(names[0]) && isCapitalized(names[1]));
    }

    Doesn't this violate EXP01-J. Never dereference null pointers? Shouldn't the parameter explicitely checked? In that case the NullPointerException has to be explicitly thrown. At least I would prefer that, because:

    1. it clearly documents, that this method does not work with null parameter,
    2. it does not make any difference for the caller and
    3. it does violate EXP01-J. Never dereference null pointers

    Are there any other differences between explicitely throwing the NullPointerException or let the JVM do it implicitely, like performance disadvantages?

    Update: I set the EXP01-J rule in question. Look at the comments of that rule.

    1. Good question, but I suspect responses to this question belong with EXP01-J. Never dereference null pointers rather than with this rule, so I've addressed it there.

  7. I wrote an article about how to avoid NullPointerException. See it here.

     

  8. Dan P made the following argument:

    Typically, if some Java code catches NullPointerException, then it suppresses a null pointer dereference.
    Consequently, the program resumes execution, with data corruption (some reference is unexpectedly null).
    The program will then encounter another NullPointerException, which, if uncaught, terminates the program.
    So the consequence of catching NullPointerException is that the program dies later, long after the original null pointer occurred.
    This makes it much harder to find the bug (the original null pointer).
    But this rule does not prevent the program from terminating abnormally, it merely makes the program 'fail fast'.

    Our CERT rules are about secure coding, which aims to prevent programs from enabling malicious code execution, information leakage, or abnormal termination. But this rule accomplshes none of that; it merely makes a program terminate immediately when a null pointer is encountered, rather than later on.

    By that argument, ERR08-J should not be a hard-and-fast rule, but rather a recommendation.

  9. I do this sometimes, typically in cases like the Exception Example 2. I agree it shouldn’t be a general practice, but it has its benefits. The reason I do it is that inside other peoples’ code, I don’t necessarily know what can or cannot be null until I’ve run into a situation (my code just glues library A with library B). I catch NPEs when there’s a conflict: some part of a piece I don’t control needs something null and I have to integrate it with another piece that doesn’t deal with nulls.

    Lately I've been violating this in iteration control. When moving through a bunch of artifacts, catching the basic "Exception" lets me track which items had something go wrong, while continuing to get information on the rest. Without catching the base Exception (or NPE), it would be hard to track which thing went wrong and figure out where to resume next time, given that things aren't always sorted the same.

    One ideal solution to this is to use Java 8’s Type Annotations and mark something as @NonNull with the checker-framework: http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#nullness-checker

    1. Your first paragraph sounds like the software equivalent of duct tape Useful for getting stuff done, but not something you'd want others to rely on. (smile) I suppose it is more work, but you should be able to prevent NPEs with suitable null checks in your glue code.

      Your second example is valid, and is covered by ERR08-EX2.

      Finally, we should add a compliant solution that uses @NonNull.

  10. A quick observation: https://github.com/spotbugs/spotbugs/issues/1954 notes a number of cases where Java Collections document NPE as possibly being thrown. These cases are not covered by the Exceptions section, but most likely there should be, as catching NPE in these cases is actually proper defensiveness.

    As an example of a perfectly-fine code requiring suppression of this error I submit this code snippet.

    1. This is a good question, and deserves careful thought. Some more background:

      According to the Java 8 Collection.contains() API doc:
      https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#contains-java.lang.Object-

      Collection.contains() can throw a NullPointerException only if it is invoked with a null object and a container that can not hold null objects (which is allowed by Java's collection framework). In such a case calling contains() indicates a program bug, much like a failed assertion, or any other NullPointerException :)

      I do not like the notion of a NullPointerException produced by contains() being suppressed. Exceptions that definitely indicate a that the code contains a bug should never be suppressed, and the conditions in which the program should be allowed to continue are rare.

      So considering the "defensive code" example from the Github link:
      If the defensive code knew whether the container allows nulls, it could just test obj for null. But that is not possible if the defensive code does not know.  It would be nice if containers provided some allowsNull() method to test this at runtime :)

      First, what is wrong with letting the NullPointerException propagate outside the defensive code? It does indicate a bug in the calling code.

      You could always apply ERR08-J-EX0 and have your defensive code wrap NullPointerException (and ClassCastException, while you're at it) in some other exception, such as java.lang.IllegalArgumentException.

      Finally, if your code is truly 'defensive' you could claim that it is covered by ERR08-J-EX2.