1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
/* 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* source (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)
{
extern void free (void*);
extern void* realloc (void*, size_t);
{
void *p = realloc (source (), 1);
p = realloc_A (p, 2);
__builtin_free (p);
}
{
void *p = realloc (source (), 2);
p = realloc_A (p, 2);
free (p);
}
{
void *p = realloc (source (), 3);
free (p);
}
{
void *p = realloc (source (), 4);
__builtin_free (p);
}
{
void *p = realloc (source (), 5); // { dg-message "returned from 'realloc'" }
dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" }
}
}
|