mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 22:26:05 +00:00

... unless it's a literal D94640 was a bit too aggressive in its analysis, considering integers representing valid addresses as invalid. This change rolls back some of the check, so that only the most obvious case is still flagged. Before: ```cpp free((void*)1000); // literal converted to `void*`: warning good free((void*)an_int); // `int` object converted to `void*`: warning might // be a false positive ``` After ```cpp free((void*)1000); // literal converted to `void*`: warning good free((void*)an_int); // doesn't warn ``` Differential Revision: https://reviews.llvm.org/D97512
247 lines
7.7 KiB
C++
247 lines
7.7 KiB
C++
// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-store=region \
|
|
// RUN: -analyzer-checker=core \
|
|
// RUN: -analyzer-checker=unix.Malloc
|
|
//
|
|
// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-store=region \
|
|
// RUN: -analyzer-checker=core \
|
|
// RUN: -analyzer-checker=unix.Malloc \
|
|
// RUN: -analyzer-config unix.DynamicMemoryModeling:Optimistic=true
|
|
namespace std {
|
|
using size_t = decltype(sizeof(int));
|
|
void free(void *);
|
|
}
|
|
|
|
extern "C" void free(void *);
|
|
extern "C" void *alloca(std::size_t);
|
|
|
|
void t1a () {
|
|
int a[] = { 1 };
|
|
free(a);
|
|
// expected-warning@-1{{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t1b () {
|
|
int a[] = { 1 };
|
|
std::free(a);
|
|
// expected-warning@-1{{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t2a () {
|
|
int a = 1;
|
|
free(&a);
|
|
// expected-warning@-1{{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t2b () {
|
|
int a = 1;
|
|
std::free(&a);
|
|
// expected-warning@-1{{Argument to free() is the address of the local variable 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t3a () {
|
|
static int a[] = { 1 };
|
|
free(a);
|
|
// expected-warning@-1{{Argument to free() is the address of the static variable 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t3b () {
|
|
static int a[] = { 1 };
|
|
std::free(a);
|
|
// expected-warning@-1{{Argument to free() is the address of the static variable 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t4a (char *x) {
|
|
free(x); // no-warning
|
|
}
|
|
|
|
void t4b (char *x) {
|
|
std::free(x); // no-warning
|
|
}
|
|
|
|
void t5a () {
|
|
extern char *ptr();
|
|
free(ptr()); // no-warning
|
|
}
|
|
|
|
void t5b () {
|
|
extern char *ptr();
|
|
std::free(ptr()); // no-warning
|
|
}
|
|
|
|
void t6a () {
|
|
free((void*)1000);
|
|
// expected-warning@-1{{Argument to free() is a constant address (1000), which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object '(void *)1000'}}
|
|
}
|
|
|
|
void t6b () {
|
|
std::free((void*)1000);
|
|
// expected-warning@-1{{Argument to free() is a constant address (1000), which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object '(void *)1000'}}
|
|
}
|
|
|
|
void t7a (char **x) {
|
|
free(*x); // no-warning
|
|
}
|
|
|
|
void t7b (char **x) {
|
|
std::free(*x); // no-warning
|
|
}
|
|
|
|
void t8a (char **x) {
|
|
// ugh
|
|
free((*x)+8); // no-warning
|
|
}
|
|
|
|
void t8b (char **x) {
|
|
// ugh
|
|
std::free((*x)+8); // no-warning
|
|
}
|
|
|
|
void t9a () {
|
|
label:
|
|
free(&&label);
|
|
// expected-warning@-1{{Argument to free() is the address of the label 'label', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 'label'}}
|
|
}
|
|
|
|
void t9b () {
|
|
label:
|
|
std::free(&&label);
|
|
// expected-warning@-1{{Argument to free() is the address of the label 'label', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 'label'}}
|
|
}
|
|
|
|
void t10a () {
|
|
free((void*)&t10a);
|
|
// expected-warning@-1{{Argument to free() is the address of the function 't10a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 't10a'}}
|
|
}
|
|
|
|
void t10b () {
|
|
std::free((void*)&t10b);
|
|
// expected-warning@-1{{Argument to free() is the address of the function 't10b', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 't10b'}}
|
|
}
|
|
|
|
void t11a () {
|
|
char *p = (char*)alloca(2);
|
|
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
|
|
}
|
|
|
|
void t11b () {
|
|
char *p = (char*)alloca(2);
|
|
std::free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
|
|
}
|
|
|
|
void t12a () {
|
|
char *p = (char*)__builtin_alloca(2);
|
|
free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
|
|
}
|
|
|
|
void t12b () {
|
|
char *p = (char*)__builtin_alloca(2);
|
|
std::free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
|
|
}
|
|
|
|
void t13a () {
|
|
free(^{return;});
|
|
// expected-warning@-1{{Argument to free() is a block, which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object: block expression}}
|
|
}
|
|
|
|
void t13b () {
|
|
std::free(^{return;});
|
|
// expected-warning@-1{{Argument to free() is a block, which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object: block expression}}
|
|
}
|
|
|
|
void t14a () {
|
|
free((void *)+[]{ return; });
|
|
// expected-warning@-1{{Argument to free() is the address of the function '__invoke', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object: lambda-to-function-pointer conversion}}
|
|
}
|
|
|
|
void t14b () {
|
|
std::free((void *)+[]{ return; });
|
|
// expected-warning@-1{{Argument to free() is the address of the function '__invoke', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object: lambda-to-function-pointer conversion}}
|
|
}
|
|
|
|
void t15a (char a) {
|
|
free(&a);
|
|
// expected-warning@-1{{Argument to free() is the address of the parameter 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 'a'}}
|
|
}
|
|
|
|
void t15b (char a) {
|
|
std::free(&a);
|
|
// expected-warning@-1{{Argument to free() is the address of the parameter 'a', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 'a'}}
|
|
}
|
|
|
|
static int someGlobal[2];
|
|
void t16a () {
|
|
free(someGlobal);
|
|
// expected-warning@-1{{Argument to free() is the address of the global variable 'someGlobal', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call free on non-heap object 'someGlobal'}}
|
|
}
|
|
|
|
void t16b () {
|
|
std::free(someGlobal);
|
|
// expected-warning@-1{{Argument to free() is the address of the global variable 'someGlobal', which is not memory allocated by malloc()}}
|
|
// expected-warning@-2{{attempt to call std::free on non-heap object 'someGlobal'}}
|
|
}
|
|
|
|
void t17a (char **x, int offset) {
|
|
// Unknown value
|
|
free(x[offset]); // no-warning
|
|
}
|
|
|
|
void t17b (char **x, int offset) {
|
|
// Unknown value
|
|
std::free(x[offset]); // no-warning
|
|
}
|
|
|
|
struct S {
|
|
const char* p;
|
|
};
|
|
|
|
void t18_C_style_C_style_free (S s) {
|
|
free((void*)(unsigned long long)s.p); // no warning
|
|
}
|
|
|
|
void t18_C_style_C_style_std_free (S s) {
|
|
std::free((void*)(unsigned long long)s.p); // no warning
|
|
}
|
|
|
|
void t18_C_style_reinterpret_free (S s) {
|
|
free((void*)reinterpret_cast<unsigned long long>(s.p)); // no warning
|
|
}
|
|
|
|
void t18_C_style_reinterpret_std_free (S s) {
|
|
std::free((void*)reinterpret_cast<unsigned long long>(s.p)); // no warning
|
|
}
|
|
|
|
void t18_reinterpret_C_style_free (S s) {
|
|
free(reinterpret_cast<void*>((unsigned long long)(s.p))); // no warning
|
|
}
|
|
|
|
void t18_reinterpret_C_style_std_free (S s) {
|
|
std::free(reinterpret_cast<void*>((unsigned long long)(s.p))); // no warning
|
|
}
|
|
|
|
void t18_reinterpret_reinterpret_free (S s) {
|
|
free(reinterpret_cast<void*>(reinterpret_cast<unsigned long long>(s.p))); // no warning
|
|
}
|
|
|
|
void t18_reinterpret_reinterpret_std_free (S s) {
|
|
std::free(reinterpret_cast<void*>(reinterpret_cast<unsigned long long>(s.p))); // no warning
|
|
}
|