Semmle 1.21
Skip to end of metadata
Go to start of metadata

Name: Inconsistent null check of pointer

Description: A dereferenced pointer is not checked for nullness in this location, but it is checked in other locations. Dereferencing a null pointer leads to undefined results.

ID: cpp/inconsistent-nullness-testing

Kind: problem

Severity: warning

Query: InconsistentNullnessTesting.ql
/**
 * @name Inconsistent null check of pointer
 * @description A dereferenced pointer is not checked for nullness in this location, but it is checked in other locations. Dereferencing a null pointer leads to undefined results.
 * @kind problem
 * @id cpp/inconsistent-nullness-testing
 * @problem.severity warning
 * @tags reliability
 *       security
 *       external/cwe/cwe-476
 */

import cpp

from LocalScopeVariable v, ControlFlowNode def, VariableAccess checked, VariableAccess unchecked
where
  checked = v.getAnAccess() and
  dereferenced(checked) and
  unchecked = v.getAnAccess() and
  dereferenced(unchecked) and
  definitionUsePair(v, def, checked) and
  definitionUsePair(v, def, unchecked) and
  checkedValid(v, checked) and
  not checkedValid(v, unchecked) and
  not unchecked.getParent+() instanceof SizeofOperator and
  forall(ControlFlowNode other | definitionUsePair(v, other, checked) |
    definitionUsePair(v, other, unchecked)
  )
select unchecked,
  "This dereference is not guarded by a non-null check, whereas other dereferences are guarded"

This query finds pointer dereferences that do not first check the pointer for nullness, even though the same pointer is checked for nullness in other parts of the code. It is likely that the nullness check was accidentally omitted, and that a null pointer dereference can occur. Dereferencing a null pointer and attempting to modify its contents can lead to anything from a segmentation fault to corrupting important system data (including the interrupt table in some architectures).

This check is an approximation, so some results may not be actual defects in the program. It is not possible in general to compute the values of pointers without running the program with all input data.

Recommendation

Use a nullness check consistently in all cases where a pointer is dereferenced.

Example

This code shows two examples where a pointer is dereferenced. The first example checks that the pointer is not null before dereferencing it. The second example fails to perform a nullness check, leading to a potential vulnerability in the code.

void* f() {
	block = (MyBlock *)malloc(sizeof(MyBlock));
	if (block) { //correct: block is checked for nullness here
		block->id = NORMAL_BLOCK_ID;
	}
	//...
	/* make sure data-portion is null-terminated */
	block->data[BLOCK_SIZE - 1] = '\0'; //wrong: block not checked for nullness here
	return block;
}

References