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

Name: Pointer to stack object used as return value

Description: Using a pointer to stack memory after the function has returned gives undefined results.

ID: cpp/return-stack-allocated-object

Kind: problem

Severity: warning

Query: ReturnStackAllocatedObject.ql
/**
 * @name Pointer to stack object used as return value
 * @description Using a pointer to stack memory after the function has returned gives undefined results.
 * @kind problem
 * @id cpp/return-stack-allocated-object
 * @problem.severity warning
 * @tags reliability
 *       security
 *       external/cwe/cwe-562
 */
import semmle.code.cpp.pointsto.PointsTo

class ReturnPointsToExpr extends PointsToExpr
{
  override predicate interesting() {
    exists(ReturnStmt ret | ret.getExpr().getFullyConverted() = this)
    and pointerValue(this)
  }

  ReturnStmt getReturnStmt() { result.getExpr().getFullyConverted() = this }
}

from ReturnPointsToExpr ret, LocalVariable local, float confidence
where ret.pointsTo() = local
  and ret.getReturnStmt().getEnclosingFunction() = local.getFunction()
  and not(local.isStatic())
  and confidence = ret.confidence()
  and confidence > 0.01
select ret,
  "This may return a pointer to '" + local.getName() +
  "' (declared on line " + local.getADeclarationLocation().getStartLine().toString() +
  "), which is stack allocated."

This query finds return statements that return pointers to an object allocated on the stack. The lifetime of a stack allocated memory location only lasts until the function returns, and the contents of that memory become undefined after that. Clearly, using a pointer to stack memory after the function has already returned will have undefined results.

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

Do not return pointers to stack memory locations. Instead, create an output parameter, or create a heap-allocated buffer. You can then copy the contents of the stack-allocated memory to the heap-allocated buffer and return that location instead.

Example

The example below the reference to myRecord is useful only while the containing function is running. If you need to access the object outside this function, either create an output parameter with its value, or copy the object into heap-allocated memory.

Record* fixRecord(Record* r) {
	Record myRecord = *r;
	delete r;

	myRecord.fix();
	return &myRecord; //returns reference to myRecord, which is a stack-allocated object
}

References