blob: 21a5ea7c5dab3289d99d89e1074df532cbc7a681 [file] [log] [blame]
/* 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" }
}
}