Skip to content

[BUG] False positive: "Returning reference to local variable" for pointer (void*) return values when @safe annotation present #7

@daggergad7

Description

@daggergad7

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

  1. 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;
}
  1. 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:

  1. p is a pointer, not a referencevoid* stores an address value, not a reference to local storage
  2. malloc returns heap memory — the allocated memory persists after the function returns
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions