Summary
void* p = malloc(sz); return p; is incorrectly reported as "Returning reference to local variable 'p'" when the same file contains any function with @safe annotation. The checker conflates pointer returns with reference returns.
Environment
- Checker version: commit 403d39f (main)
- OS: Linux
- Clang/LLVM: 14
Reproduction
- Create
test_void_return.cpp:
#include <stdlib.h>
template <typename T>
class circular_int {
public:
// @safe
circular_int() : v_() {}
// @unsafe
// @lifetime: (&'a mut) -> &'a mut
circular_int<T> &operator++() { ++v_; return *this; }
private:
T v_;
};
class allocator {
public:
void* allocate(size_t sz) {
void* p = malloc(sz);
return p; // FALSE POSITIVE
}
};
int main() {
circular_int<int> ci; ++ci;
allocator a;
void* mem = a.allocate(100);
free(mem);
return 0;
}
- Run:
./rusty-cpp-checker test_void_return.cpp
Actual output:
✗ Found 1 violation(s) in test_void_return.cpp:
Returning reference to local variable 'p' - this will create a dangling reference
Expected output: No violations.
Additional Observations
- Removing the
@safe annotation makes the false positive disappear
- Removing the template class entirely makes the false positive disappear
- The bug is triggered specifically by presence of
@safe annotation anywhere in the file
Why This Is Safe
The code void* p = malloc(sz); return p; is safe because:
p is a pointer, not a reference — void* stores an address value, not a reference to local storage
malloc returns heap memory — the allocated memory persists after the function returns
- Return copies the pointer value — when returning
p, the address value is copied to the caller; the local variable p being destroyed doesn't affect the heap memory it pointed to
This is fundamentally different from returning a reference to a stack variable:
// UNSAFE: reference to stack
int& bad() { int x = 42; return x; } // x destroyed, dangling reference
// SAFE: pointer to heap
void* good(size_t sz) { void* p = malloc(sz); return p; } // heap persists
Impact
This blocks allocator patterns (e.g., threadinfo::allocate, pool_allocate) and forces excluding files from borrow checking when they include headers with @safe annotations.
Summary
void* p = malloc(sz); return p;is incorrectly reported as "Returning reference to local variable 'p'" when the same file contains any function with@safeannotation. The checker conflates pointer returns with reference returns.Environment
Reproduction
test_void_return.cpp:./rusty-cpp-checker test_void_return.cppActual output:
Expected output: No violations.
Additional Observations
@safeannotation makes the false positive disappear@safeannotation anywhere in the fileWhy This Is Safe
The code
void* p = malloc(sz); return p;is safe because:pis a pointer, not a reference —void*stores an address value, not a reference to local storagemallocreturns heap memory — the allocated memory persists after the function returnsp, the address value is copied to the caller; the local variablepbeing destroyed doesn't affect the heap memory it pointed toThis is fundamentally different from returning a reference to a stack variable:
Impact
This blocks allocator patterns (e.g.,
threadinfo::allocate,pool_allocate) and forces excluding files from borrow checking when they include headers with@safeannotations.