(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
analyzer/
boxed-malloc-1.c
       1  /* Adapted from malloc-1.c, but wrapping the pointers in a struct.  */
       2  
       3  /* { dg-require-effective-target alloca } */
       4  
       5  #include <stdlib.h>
       6  
       7  extern int foo (void);
       8  extern int bar (void);
       9  extern void could_free (void *);
      10  extern void cant_free (const void *); /* since it's a const void *.  */
      11  
      12  typedef struct boxed_ptr { void *value; } boxed_ptr;
      13  
      14  boxed_ptr
      15  boxed_malloc (size_t sz)
      16  {
      17    boxed_ptr result;
      18    result.value = malloc (sz);
      19    return result;
      20  }
      21  
      22  boxed_ptr
      23  boxed_free (boxed_ptr ptr)
      24  {
      25    free (ptr.value);
      26  }
      27  
      28  const boxed_ptr boxed_null = {NULL};
      29  
      30  void test_1 (void)
      31  {
      32    boxed_ptr ptr;
      33    ptr.value = malloc (1024);
      34    free (ptr.value);
      35    free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */
      36  }
      37  
      38  void test_2 (boxed_ptr ptr)
      39  {
      40    free (ptr.value);
      41    free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */
      42  }
      43  
      44  boxed_ptr
      45  test_3 (void)
      46  {
      47    boxed_ptr ptr;
      48    ptr.value = malloc (sizeof (int));
      49    *(int *)ptr.value = 42; /* { dg-warning "dereference of possibly-NULL 'ptr.value' \\\[CWE-690\\\]" } */
      50    return ptr;
      51  }
      52  
      53  boxed_ptr
      54  test_4 (void)
      55  {
      56    boxed_ptr ptr;
      57    ptr.value = malloc (sizeof (int));
      58    int *iptr = (int *)ptr.value;
      59    if (iptr)
      60      *iptr = 42;
      61    else
      62      *iptr = 43; /* { dg-warning "dereference of NULL 'iptr' \\\[CWE-476\\\]" } */
      63    return ptr;
      64  }
      65  
      66  int test_5 (boxed_ptr ptr)
      67  {
      68    free (ptr.value);
      69    return *(int *)ptr.value; /* { dg-warning "use after 'free' of 'ptr.value'" } */
      70  }
      71  
      72  void test_6 (void *ptr)
      73  {
      74    boxed_ptr q;
      75    q.value = ptr;
      76    free (ptr);
      77    free (q.value); /* { dg-warning "double-'free' of 'ptr'" } */
      78  }
      79  
      80  void test_6a (boxed_ptr ptr)
      81  {
      82    boxed_ptr q;
      83    q = ptr;
      84    boxed_free (ptr);
      85    free (q.value); /* { dg-warning "double-'free' of 'ptr.value'" } */
      86  }
      87  
      88  void test_7 (void)
      89  {
      90    boxed_ptr ptr = boxed_malloc(4096);
      91    if (!ptr.value)
      92      return;
      93    __builtin_memset(ptr.value, 0, 4096);
      94    boxed_free(ptr);
      95  }
      96  
      97  boxed_ptr test_8 (void)
      98  {
      99    boxed_ptr ptr = boxed_malloc(4096);
     100    if (!ptr.value)
     101      return boxed_null;
     102    __builtin_memset(ptr.value, 0, 4096);
     103    return ptr;
     104  }
     105  
     106  void test_9 (void)
     107  {
     108    boxed_ptr ptr = boxed_malloc (1024);
     109  
     110    int i;
     111    for (i = 0; i < 1024; i++)
     112      free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */
     113  }
     114  
     115  void test_10 (void)
     116  {
     117    boxed_ptr ptr = boxed_malloc (1024);
     118  
     119    int i;
     120    for (i = 0; i < 1024; i++)
     121      foo ();
     122  
     123    free (ptr.value);
     124    free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ 
     125  }
     126  
     127  void test_11 (void)
     128  {
     129    boxed_ptr ptr = boxed_malloc (1024);
     130  
     131    while (foo ())
     132      bar ();
     133  
     134    free (ptr.value);
     135    free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */
     136  }
     137  
     138  void test_12 (void)
     139  {
     140    boxed_ptr ptr = boxed_malloc (1024);
     141  
     142    while (1)
     143      {
     144        free (ptr.value);
     145        free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */
     146      }
     147  }
     148  
     149  void test_13 (void)
     150  {
     151    boxed_ptr p = boxed_malloc (1024);
     152    boxed_ptr q = boxed_malloc (1024);
     153  
     154    foo ();
     155    if (!q.value)
     156      {
     157        boxed_free (q);
     158        return; /* { dg-warning "leak of 'p.value'" } */ 
     159      }
     160    bar ();
     161    boxed_free (q);
     162    boxed_free (p);
     163  }
     164  
     165  void test_14 (void)
     166  {
     167    boxed_ptr p, q;
     168    p = boxed_malloc (1024);
     169    if (!p.value)
     170      return;
     171  
     172    q = boxed_malloc (1024);
     173    if (!q.value)
     174      {
     175        boxed_free (p);
     176        boxed_free (q);
     177        /* oops: missing "return".  */
     178      }
     179    bar ();
     180    boxed_free (q); /* Although this looks like a double-'free' of q,
     181  	       it's known to be NULL for the case where free is
     182  	       called twice on it.  */
     183    free (p.value); /* { dg-warning "double-'free' of 'p.value'" } */
     184  }
     185  
     186  void test_15 (void)
     187  {
     188    boxed_ptr p, q;
     189    p.value = NULL;
     190    q.value = NULL;
     191  
     192    p = boxed_malloc (1024);
     193    if (!p.value)
     194      goto fail;
     195  
     196    foo ();
     197  
     198    q = boxed_malloc (1024);
     199    if (!q.value)
     200      goto fail;
     201  
     202    bar ();
     203  
     204   fail:
     205    boxed_free (q);
     206    boxed_free (p);
     207  }
     208  
     209  void test_16 (void)
     210  {
     211    boxed_ptr p, q; /* { dg-message "region created on stack here" } */
     212  
     213    p = boxed_malloc (1024);
     214    if (!p.value)
     215      goto fail;
     216  
     217    foo ();
     218  
     219    q = boxed_malloc (1024);
     220    if (!q.value)
     221      goto fail;
     222  
     223    bar ();
     224  
     225   fail:
     226    boxed_free (q); /* { dg-warning "use of uninitialized value 'q'" } */
     227    boxed_free (p);
     228  }
     229  
     230  void test_17 (void)
     231  {
     232    boxed_ptr ptr = boxed_malloc (1024);
     233  } /* { dg-warning "leak of 'ptr.value'" } */ 
     234  
     235  void test_18 (void)
     236  {
     237    boxed_ptr ptr = boxed_malloc (64);
     238    ptr = boxed_null; /* { dg-warning "leak of 'ptr.value'" } */ 
     239  }
     240  
     241  void test_18a (void)
     242  {
     243    boxed_ptr ptr = boxed_malloc (64);
     244    ptr.value = NULL; /* { dg-warning "leak of 'ptr.value'" } */ 
     245  }
     246  
     247  void test_19 (void)
     248  {
     249    boxed_ptr ptr = boxed_malloc (64);
     250    free (ptr.value);
     251    ptr.value = NULL;
     252    free (ptr.value);
     253  }
     254  
     255  boxed_ptr global_ptr_20;
     256  
     257  void test_20 (void)
     258  {
     259    global_ptr_20 = boxed_malloc (1024);
     260  }
     261  
     262  int *test_21 (int i)
     263  {
     264    boxed_ptr ptr = boxed_malloc (sizeof (int));
     265    if (!ptr.value)
     266      abort ();
     267    *(int *)ptr.value = i;
     268    return ptr.value;
     269  }
     270  
     271  boxed_ptr test_21a (int i)
     272  {
     273    boxed_ptr ptr = boxed_malloc (sizeof (int));
     274    if (!ptr.value)
     275      abort ();
     276    *(int *)ptr.value = i;
     277    return ptr;
     278  }
     279  
     280  void test_22 (void)
     281  {
     282    boxed_ptr ptr = boxed_malloc (1024);
     283  
     284    int i;
     285    for (i = 5; i < 10; i++)
     286      foo ();
     287  
     288    free (ptr.value);
     289    free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ 
     290  }
     291  
     292  int test_24 (void)
     293  {
     294    boxed_ptr ptr;
     295    ptr.value = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */
     296    free (ptr.value); /* { dg-warning "'free' of 'ptr.value' which points to memory on the stack \\\[CWE-590\\\]" } */
     297  }
     298  
     299  int test_25 (void)
     300  {
     301    char tmp[100]; /* { dg-message "region created on stack here" } */
     302    boxed_ptr p;
     303    p.value = tmp;
     304    free (p.value); /* { dg-warning "'free' of '&tmp' which points to memory on the stack \\\[CWE-590\\\]" } */
     305  }
     306  
     307  char global_buffer[100]; /* { dg-message "region created here" } */
     308  
     309  int test_26 (void)
     310  {
     311    boxed_ptr p;
     312    p.value = global_buffer;
     313    free (p.value); /* { dg-warning "'free' of '&global_buffer' which points to memory not on the heap \\\[CWE-590\\\]" } */
     314  }
     315  
     316  struct coord {
     317    float x;
     318    float y;
     319  };
     320  
     321  boxed_ptr test_27 (void)
     322  {
     323    boxed_ptr p = boxed_malloc (sizeof (struct coord));
     324    ((struct coord *)p.value)->x = 0.f;  /* { dg-warning "dereference of possibly-NULL 'p.value' \\\[CWE-690\\\]" } */
     325  
     326    /* Only the first such usage should be reported: */
     327    ((struct coord *)p.value)->y = 0.f;
     328  
     329    return p;
     330  }
     331  
     332  struct link
     333  {
     334    boxed_ptr m_ptr;
     335  };
     336  
     337  boxed_ptr test_29 (void)
     338  {
     339    boxed_ptr res = boxed_malloc (sizeof (struct link));
     340    if (!res.value)
     341      return boxed_null;
     342    ((struct link *)res.value)->m_ptr = boxed_malloc (sizeof (struct link));
     343    return res;
     344  }
     345  
     346  void test_31 (void)
     347  {
     348    struct link tmp;
     349    boxed_ptr ptr = boxed_malloc (sizeof (struct link));
     350    tmp.m_ptr = ptr;
     351  } /* { dg-warning "leak" } */ 
     352  
     353  void test_32 (void)
     354  {
     355    boxed_ptr ptr = boxed_malloc (1024);
     356    could_free (ptr.value);
     357  } /* { dg-bogus "leak" } */
     358  
     359  void test_33 (void)
     360  {
     361    boxed_ptr ptr = boxed_malloc (1024);
     362    cant_free (ptr.value);
     363  } /* { dg-warning "leak of 'ptr.value'" } */ 
     364  
     365  void test_34 (void)
     366  {
     367    float *q;
     368    boxed_ptr p = boxed_malloc (sizeof (struct coord));
     369    if (!p.value)
     370      return;
     371    ((struct coord *)p.value)->x = 0.0f;
     372    q = &((struct coord *)p.value)->x;
     373    boxed_free (p);
     374    *q = 1.0f; /* { dg-warning "use after 'free' of 'q'" } */
     375  };
     376  
     377  int test_35 (void)
     378  {
     379    boxed_ptr ptr = boxed_malloc(4096);
     380    if (!ptr.value)
     381      return -1;
     382    __builtin_memset(ptr.value, 0, 4096);
     383    boxed_free(ptr);
     384    return 0;
     385  }
     386  
     387  void test_36 (void)
     388  {
     389    boxed_ptr ptr = boxed_malloc(4096);
     390    if (!ptr.value)
     391      return;
     392    __builtin_memset(ptr.value, 0, 4096);
     393    boxed_free(ptr);
     394  }
     395  
     396  boxed_ptr test_37a (void)
     397  {
     398    boxed_ptr ptr = boxed_malloc(4096);
     399    __builtin_memset(ptr.value, 0, 4096); /* { dg-warning "use of possibly-NULL 'ptr.value' where non-null expected \\\[CWE-690\\\]" } */
     400    return ptr;
     401  }
     402  
     403  int test_37b (void)
     404  {
     405    boxed_ptr p = boxed_malloc(4096);
     406    boxed_ptr q = boxed_malloc(4096);
     407    if (p.value) {
     408      __builtin_memset(p.value, 0, 4096); /* Not a bug: checked */
     409    } else {
     410      __builtin_memset(q.value, 0, 4096); /* { dg-warning "use of possibly-NULL 'q.value' where non-null expected \\\[CWE-690\\\]" } */
     411    }
     412    boxed_free(p);
     413    boxed_free(q);
     414    return 0;
     415  }
     416  
     417  extern void might_use_ptr (void *ptr);
     418  
     419  void test_38(int i)
     420  {
     421    boxed_ptr p;
     422  
     423    p = boxed_malloc(1024);
     424    if (p.value) {
     425      boxed_free(p);
     426      might_use_ptr(p.value); /* { dg-warning "use after 'free' of 'p.value'" "" { xfail *-*-* } } */
     427      // TODO: xfail
     428    }
     429  }
     430  
     431  boxed_ptr
     432  test_39 (int i)
     433  {
     434    boxed_ptr p = boxed_malloc(sizeof(int*));
     435    *(int *)p.value = i; /* { dg-warning "dereference of possibly-NULL 'p.value' \\\[CWE-690\\\]" } */
     436    return p;
     437  }
     438  
     439  boxed_ptr
     440  test_41 (int flag)
     441  {
     442    boxed_ptr buffer;
     443  
     444    if (flag) {
     445      buffer = boxed_malloc(4096);
     446    } else {
     447      buffer = boxed_null;
     448    }
     449  
     450    ((char *)buffer.value)[0] = 'a'; /* { dg-warning "dereference of possibly-NULL 'buffer.value' \\\[CWE-690\\\]" "possibly-NULL" } */
     451    /* { dg-warning "dereference of NULL" "NULL" { target *-*-* } .-1 } */
     452  
     453    return buffer;
     454  }
     455  
     456  extern void might_take_ownership (boxed_ptr ptr);
     457  
     458  void test_45 (void)
     459  {
     460    boxed_ptr p = boxed_malloc (1024);
     461    might_take_ownership (p);
     462  }
     463  
     464  /* Free of function, and of label within function.  */
     465  
     466  void test_50a (void)
     467  {
     468  }
     469  
     470  void test_50b (void)
     471  {
     472    boxed_ptr ptr;
     473    ptr.value = test_50a;
     474    free (ptr.value); /* { dg-warning "'free' of '&test_50a' which points to memory not on the heap \\\[CWE-590\\\]" } */
     475  }
     476  
     477  void test_50c (void)
     478  {
     479   my_label:
     480    boxed_ptr ptr;
     481    ptr.value = &&my_label;
     482    free (ptr.value); /* { dg-warning "'free' of '&my_label' which points to memory not on the heap \\\[CWE-590\\\]" } */
     483  }
     484  
     485  /* { dg-prune-output "\\\[-Wfree-nonheap-object" } */