diff options
Diffstat (limited to 'gcc/testsuite/gcc.dg/Wmismatched-dealloc-2.c')
-rw-r--r-- | gcc/testsuite/gcc.dg/Wmismatched-dealloc-2.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.dg/Wmismatched-dealloc-2.c b/gcc/testsuite/gcc.dg/Wmismatched-dealloc-2.c new file mode 100644 index 0000000..21a5ea7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wmismatched-dealloc-2.c @@ -0,0 +1,141 @@ +/* PR middle-end/94527 - Add an attribute that marks a function as freeing + an object + Verify that attribute malloc with one or two arguments has the expected + effect on diagnostics. + { dg-options "-Wall -ftrack-macro-expansion=0" } */ + +#define A(...) __attribute__ ((malloc (__VA_ARGS__), noipa)) + +typedef __SIZE_TYPE__ size_t; +typedef struct A A; +typedef struct B B; + +/* A pointer returned by any of the four functions must be deallocated + either by dealloc() or by realloc_{A,B}(). */ +A (__builtin_free) A* alloc_A (int); +A (__builtin_free) B* alloc_B (int); +A (__builtin_free) A* realloc_A (A *p, int n) { return p; } +A (__builtin_free) B* realloc_B (B *p, int n) { return p; } + +A (realloc_A) A* alloc_A (int); +A (realloc_B) B* alloc_B (int); +A (realloc_A) A* realloc_A (A*, int); +A (realloc_B) B* realloc_B (B*, int); + +void dealloc (void*); +A (dealloc) void* alloc (int); + +void sink (void*); + +void test_alloc_A (void) +{ + { + void *p = alloc_A (1); + p = realloc_A (p, 2); + __builtin_free (p); + } + + { + void *p = alloc_A (1); + /* Verify that calling realloc doesn't trigger a warning even though + alloc_A is not directly associated with it. */ + p = __builtin_realloc (p, 2); + sink (p); + } + + { + void *p = alloc_A (1); // { dg-message "returned from 'alloc_A'" } + dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" } + } + + { + /* Because alloc_A() and realloc_B() share free() as a deallocator + they must also be valid as each other's deallocators. */ + void *p = alloc_A (1); + p = realloc_B ((B*)p, 2); + __builtin_free (p); + } + + { + void *p = alloc_A (1); + p = realloc_A (p, 2); + p = __builtin_realloc (p, 3); + __builtin_free (p); + } +} + + +void test_realloc_A (void *ptr) +{ + { + void *p = realloc_A (0, 1); + p = realloc_A (p, 2); + __builtin_free (p); + } + + { + void *p = realloc_A (ptr, 2); + p = realloc_A (p, 2); + __builtin_free (p); + } + + { + void *p = realloc_A (0, 3); + p = __builtin_realloc (p, 2); + sink (p); + } + + { + void *p = realloc_A (0, 4); // { dg-message "returned from 'realloc_A'" } + dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" } + } + + { + /* Because realloc_A() and realloc_B() share free() as a deallocator + they must also be valid as each other's deallocators. */ + void *p = realloc_A (0, 5); + p = realloc_B ((B*)p, 2); + __builtin_free (p); + } + + { + void *p = realloc_A (0, 6); + p = realloc_A ((A*)p, 2); + p = __builtin_realloc (p, 3); + __builtin_free (p); + } +} + + +void test_realloc (void *ptr) +{ + extern void free (void*); + extern void* realloc (void*, size_t); + + { + void *p = realloc (ptr, 1); + p = realloc_A (p, 2); + __builtin_free (p); + } + + { + void *p = realloc (ptr, 2); + p = realloc_A (p, 2); + free (p); + } + + { + void *p = realloc (ptr, 3); + free (p); + } + + { + void *p = realloc (ptr, 4); + __builtin_free (p); + } + + { + void *p = realloc (ptr, 5); // { dg-message "returned from 'realloc'" } + dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" } + } +} |