Main Content

CWE Rule 562

Return of Stack Variable Address

Since R2023a

Description

Rule Description

A function returns the address of a stack variable, which will cause unintended program behavior, typically in the form of a crash.

Polyspace Implementation

The rule checker checks for Pointer or reference to stack variable leaving scope.

Examples

expand all

Issue

This issue occurs when a pointer or reference to a local variable leaves the scope of the variable. For instance:

  • A function returns a pointer to a local variable.

  • A function performs the assignment globPtr = &locVar. globPtr is a global pointer variable and locVar is a local variable.

  • A function performs the assignment *paramPtr = &locVar. paramPtr is a function parameter that is, for instance, an int** pointer and locVar is a local int variable.

  • A C++ method performs the assignment memPtr = &locVar. memPtr is a pointer data member of the class the method belongs to. locVar is a variable local to the method.

  • (C++11 and later) A function returns a lambda expression object that captures local variables of the function by reference.

The defect also applies to memory allocated using the alloca function. The defect does not apply to static, local variables. Polyspace® assumes that the local objects within a function definition are in the same scope.

Risk

Local variables are allocated an address on the stack. Once the scope of a local variable ends, this address is available for reuse. Using this address to access the local variable value outside the variable scope can cause unexpected behavior.

If a pointer to a local variable leaves the scope of the variable, Polyspace Bug Finder™ highlights the defect. The defect appears even if you do not use the address stored in the pointer. For maintainable code, it is a good practice to not allow the pointer to leave the variable scope. Even if you do not use the address in the pointer now, someone else using your function can use the address, causing undefined behavior.

Fix

Do not allow a pointer or reference to a local variable to leave the variable scope.

Example — Pointer to Local Variable Returned from Function
void func2(int *ptr) {
    *ptr = 0;
}

int* func1(void) {
    int ret = 0;  //Noncompliant
    return &ret ;
}
void main(void) {
    int* ptr = func1() ;
    func2(ptr) ;
}

In this example, func1 returns a pointer to local variable ret.

In main, ptr points to the address of the local variable. When ptr is accessed in func2, the access is illegal because the scope of ret is limited to func1,

Example — Pointer to Local Variable Escapes Through Lambda Expression
auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;  //Noncompliant
  auto adder = [&] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

In this example, the createAdder function defines a lambda expression adder that captures the local variable addThis by reference. The scope of addThis is limited to the createAdder function. When the object returned by createAdder is called, a reference to the variable addThis is accessed outside its scope. When accessed in this way, the value of addThis is undefined.

Correction – Capture Local Variables by Copy in Lambda Expression Instead of Reference

If a function returns a lambda expression object, avoid capturing local variables by reference in the lambda object. Capture the variables by copy instead.

Variables captured by copy have the same lifetime as the lambda object, but variables captured by reference often have a smaller lifetime than the lambda object itself. When the lambda object is used, these variables accessed outside scope have undefined values.

auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [=] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

Check Information

Category: Bad Coding Practices

Version History

Introduced in R2023a