Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

254 lines
9.0 KiB
C++

// RUN: %clang_analyze_cc1 -verify -analyzer-output=text %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus \
// RUN: -analyzer-checker=unix \
// RUN: -analyzer-config \
// RUN: unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes=false
// RUN: %clang_analyze_cc1 -verify=expected,ownership -analyzer-output=text %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus \
// RUN: -analyzer-checker=unix \
// RUN: -analyzer-config \
// RUN: unix.DynamicMemoryModeling:AddNoOwnershipChangeNotes=true
#include "Inputs/system-header-simulator-for-malloc.h"
// For the tests in namespace protobuf_leak:
#include "Inputs/system-header-simulator-for-protobuf.h"
//===----------------------------------------------------------------------===//
// Report for which we expect NoOwnershipChangeVisitor to add a new note.
//===----------------------------------------------------------------------===//
bool coin();
// TODO: AST analysis of sink would reveal that it doesn't intent to free the
// allocated memory, but in this instance, its also the only function with
// the ability to do so, we should see a note here.
namespace memory_allocated_in_fn_call {
void sink(int *P) {
}
void foo() {
sink(new int(5)); // expected-note {{Memory is allocated}}
} // expected-warning {{Potential memory leak [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential memory leak}}
} // namespace memory_allocated_in_fn_call
// Realize that sink() intends to deallocate memory, assume that it should've
// taken care of the leaked object as well.
namespace memory_passed_to_fn_call_delete {
void sink(int *P) {
if (coin()) // ownership-note {{Assuming the condition is false}}
// ownership-note@-1 {{Taking false branch}}
delete P;
} // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}}
void foo() {
int *ptr = new int(5); // expected-note {{Memory is allocated}}
sink(ptr); // ownership-note {{Calling 'sink'}}
// ownership-note@-1 {{Returning from 'sink'}}
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_passed_to_fn_call_delete
namespace memory_passed_to_fn_call_free {
void sink(int *P) {
if (coin()) // ownership-note {{Assuming the condition is false}}
// ownership-note@-1 {{Taking false branch}}
free(P);
} // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}}
void foo() {
int *ptr = (int *)malloc(sizeof(int)); // expected-note {{Memory is allocated}}
sink(ptr); // ownership-note {{Calling 'sink'}}
// ownership-note@-1 {{Returning from 'sink'}}
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [unix.Malloc]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_passed_to_fn_call_free
// Function pointers cannot be resolved syntactically.
namespace memory_passed_to_fn_call_free_through_fn_ptr {
void (*freeFn)(void *) = free;
void sink(int *P) {
if (coin())
freeFn(P);
}
void foo() {
int *ptr = (int *)malloc(sizeof(int)); // expected-note {{Memory is allocated}}
sink(ptr);
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [unix.Malloc]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_passed_to_fn_call_free_through_fn_ptr
namespace memory_shared_with_ptr_of_shorter_lifetime {
void sink(int *P) {
int *Q = P;
if (coin()) // ownership-note {{Assuming the condition is false}}
// ownership-note@-1 {{Taking false branch}}
delete P;
(void)Q;
} // ownership-note {{Returning without deallocating memory or storing the pointer for later deallocation}}
void foo() {
int *ptr = new int(5); // expected-note {{Memory is allocated}}
sink(ptr); // ownership-note {{Calling 'sink'}}
// ownership-note@-1 {{Returning from 'sink'}}
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_shared_with_ptr_of_shorter_lifetime
//===----------------------------------------------------------------------===//
// Report for which we *do not* expect NoOwnershipChangeVisitor add a new note,
// nor do we want it to.
//===----------------------------------------------------------------------===//
namespace memory_not_passed_to_fn_call {
void sink(int *P) {
if (coin())
delete P;
}
void foo() {
int *ptr = new int(5); // expected-note {{Memory is allocated}}
int *q = nullptr;
sink(q);
(void)ptr;
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_not_passed_to_fn_call
namespace memory_shared_with_ptr_of_same_lifetime {
void sink(int *P, int **Q) {
// NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be
// highlighted still?
*Q = P;
}
void foo() {
int *ptr = new int(5); // expected-note {{Memory is allocated}}
int *q = nullptr;
sink(ptr, &q);
} // expected-warning {{Potential leak of memory pointed to by 'q' [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_shared_with_ptr_of_same_lifetime
namespace memory_passed_into_fn_that_doesnt_intend_to_free {
void sink(int *P) {
}
void foo() {
int *ptr = new int(5); // expected-note {{Memory is allocated}}
sink(ptr);
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_passed_into_fn_that_doesnt_intend_to_free
namespace memory_passed_into_fn_that_doesnt_intend_to_free2 {
void bar();
void sink(int *P) {
// Correctly realize that calling bar() doesn't mean that this function would
// like to deallocate anything.
bar();
}
void foo() {
int *ptr = new int(5); // expected-note {{Memory is allocated}}
sink(ptr);
} // expected-warning {{Potential leak of memory pointed to by 'ptr' [cplusplus.NewDeleteLeaks]}}
// expected-note@-1 {{Potential leak}}
} // namespace memory_passed_into_fn_that_doesnt_intend_to_free2
namespace refkind_from_unoallocated_to_allocated {
// RefKind of the symbol changed from nothing to Allocated. We don't want to
// emit notes when the RefKind changes in the stack frame.
static char *malloc_wrapper_ret() {
return (char *)malloc(12); // expected-note {{Memory is allocated}}
}
void use_ret() {
char *v;
v = malloc_wrapper_ret(); // expected-note {{Calling 'malloc_wrapper_ret'}}
// expected-note@-1 {{Returned allocated memory}}
} // expected-warning {{Potential leak of memory pointed to by 'v' [unix.Malloc]}}
// expected-note@-1 {{Potential leak of memory pointed to by 'v'}}
} // namespace refkind_from_unoallocated_to_allocated
// Check that memory leak is reported against a symbol if the last place it's
// mentioned is a base region of a lazy compound value, as the program cannot
// possibly free that memory.
namespace symbol_reaper_lifetime {
struct Nested {
int buf[2];
};
struct Wrapping {
Nested data;
};
Nested allocateWrappingAndReturnNested() {
// expected-note@+1 {{Memory is allocated}}
Wrapping const* p = new Wrapping();
// expected-warning@+2 {{Potential leak of memory pointed to by 'p'}}
// expected-note@+1 {{Potential leak of memory pointed to by 'p'}}
return p->data;
}
void caller() {
// expected-note@+1 {{Calling 'allocateWrappingAndReturnNested'}}
Nested n = allocateWrappingAndReturnNested();
(void)n;
} // no-warning: No potential memory leak here, because that's been already reported.
} // namespace symbol_reaper_lifetime
// Check that we do not report false positives in automatically generated
// protobuf code that passes dynamically allocated memory to a certain function
// named GetOwnedMessageInternal.
namespace protobuf_leak {
Arena *some_arena, *some_submessage_arena;
MessageLite *protobuf_leak() {
MessageLite *p = new MessageLite(); // Real protobuf code instantiates a
// subclass of MessageLite, but that's
// not relevant for the bug.
MessageLite *q = GetOwnedMessageInternal(some_arena, p, some_submessage_arena);
return q;
// No leak at end of function -- the pointer escapes in GetOwnedMessageInternal.
}
void validate_system_header() {
// The case protobuf_leak would also pass if GetOwnedMessageInternal wasn't
// declared in a system header. This test verifies that another function
// declared in the same header behaves differently (doesn't escape memory) to
// demonstrate that GetOwnedMessageInternal is indeed explicitly recognized
// by the analyzer.
// expected-note@+1 {{Memory is allocated}}
MessageLite *p = new MessageLite();
SomeOtherFunction(p);
// expected-warning@+2 {{Potential leak of memory pointed to by 'p'}}
// expected-note@+1 {{Potential leak of memory pointed to by 'p'}}
}
} // namespace protobuf_leak