/* 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__))) typedef struct FILE FILE; typedef __SIZE_TYPE__ size_t; void free (void*); void* malloc (size_t); void* realloc (void*, size_t); int fclose (FILE*); FILE* freopen (const char*, const char*, FILE*); int pclose (FILE*); A (fclose) A (freopen, 3) FILE* fdopen (int); A (fclose) A (freopen, 3) FILE* fopen (const char*, const char*); A (fclose) A (freopen, 3) FILE* fmemopen(void *, size_t, const char *); A (fclose) A (freopen, 3) FILE* freopen (const char*, const char*, FILE*); A (pclose) A (freopen, 3) FILE* popen (const char*, const char*); A (fclose) A (freopen, 3) FILE* tmpfile (void); void sink (FILE*); void release (void*); A (release) FILE* acquire (void); void nowarn_fdopen (void) { { FILE *q = fdopen (0); if (!q) return; fclose (q); } { FILE *q = fdopen (0); if (!q) return; q = freopen ("1", "r", q); fclose (q); } { FILE *q = fdopen (0); if (!q) return; sink (q); } } void warn_fdopen (void) { { FILE *q = fdopen (0); // { dg-message "returned from a call to 'fdopen'" "note" } sink (q); release (q); // { dg-warning "'release' called on pointer returned from a mismatched allocation function" } } { FILE *q = fdopen (0); // { dg-message "returned from a call to 'fdopen'" "note" } sink (q); free (q); // { dg-warning "'free' called on pointer returned from a mismatched allocation function" } } { FILE *q = fdopen (0); // { dg-message "returned from a call to 'fdopen'" "note" } sink (q); q = realloc (q, 7); // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" } sink (q); } } void nowarn_fopen (void) { { FILE *q = fopen ("1", "r"); sink (q); fclose (q); } { FILE *q = fopen ("2", "r"); sink (q); q = freopen ("3", "r", q); sink (q); fclose (q); } { FILE *q = fopen ("4", "r"); sink (q); } } void warn_fopen (void) { { FILE *q = fopen ("1", "r"); sink (q); release (q); // { dg-warning "'release' called on pointer returned from a mismatched allocation function" } } { FILE *q = fdopen (0); sink (q); free (q); // { dg-warning "'free' called on pointer returned from a mismatched allocation function" } } { FILE *q = fdopen (0); sink (q); q = realloc (q, 7); // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" } sink (q); } } void test_popen (void) { { FILE *p = popen ("1", "r"); sink (p); pclose (p); } { FILE *p; p = popen ("2", "r"); // { dg-message "returned from a call to 'popen'" "note" } sink (p); fclose (p); // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" } } { /* freopen() can close a stream open by popen() but pclose() can't close the stream returned from freopen(). */ FILE *p = popen ("2", "r"); sink (p); p = freopen ("3", "r", p); // { dg-message "returned from a call to 'freopen'" "note" } sink (p); pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } } } void test_tmpfile (void) { { FILE *p = tmpfile (); sink (p); fclose (p); } { FILE *p = tmpfile (); sink (p); p = freopen ("1", "r", p); sink (p); fclose (p); } { FILE *p = tmpfile (); // { dg-message "returned from a call to 'tmpfile'" "note" } sink (p); pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } } } void warn_malloc (void) { { FILE *p = malloc (100); // { dg-message "returned from a call to 'malloc'" "note" } sink (p); fclose (p); // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" } } { FILE *p = malloc (100); // { dg-message "returned from a call to 'malloc'" "note" } sink (p); p = freopen ("1", "r", p);// { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" } } { FILE *p = malloc (100); // { dg-message "returned from a call to 'malloc'" "note" } sink (p); pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } } } void test_acquire (void) { { FILE *p = acquire (); release (p); } { FILE *p = acquire (); sink (p); release (p); } { FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } sink (p); fclose (p); // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" } } { FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } sink (p); pclose (p); // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" } } { FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } sink (p); p = freopen ("1", "r", p); // { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" } sink (p); } { FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } sink (p); free (p); // { dg-warning "'free' called on pointer returned from a mismatched allocation function" } } { FILE *p = acquire (); // { dg-message "returned from a call to 'acquire'" "note" } sink (p); p = realloc (p, 123); // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" } sink (p); } }