1  #include "analyzer-decls.h"
       2  
       3  typedef __SIZE_TYPE__ size_t;
       4  
       5  #define NULL ((void *)0)
       6  
       7  extern void *calloc (size_t __nmemb, size_t __size)
       8    __attribute__ ((__nothrow__ , __leaf__))
       9    __attribute__ ((__malloc__))
      10    __attribute__ ((__alloc_size__ (1, 2))) ;
      11  extern void *malloc (size_t __size)
      12    __attribute__ ((__nothrow__ , __leaf__))
      13    __attribute__ ((__malloc__))
      14    __attribute__ ((__alloc_size__ (1)));
      15  extern void *realloc (void *__ptr, size_t __size)
      16    __attribute__ ((__nothrow__ , __leaf__))
      17    __attribute__ ((__warn_unused_result__))
      18    __attribute__ ((__alloc_size__ (2)));
      19  extern void free (void *__ptr)
      20    __attribute__ ((__nothrow__ , __leaf__));
      21  
      22  /* realloc where we don't know the original size of the region.  */
      23  
      24  char *test_8 (char *p, size_t sz)
      25  {
      26    char *q;
      27  
      28    __analyzer_dump_capacity (p); /* { dg-warning "capacity: 'UNKNOWN\\(\[^\n\r\]*\\)'" } */
      29  
      30    p[0] = 'a';
      31    p[1] = 'b';
      32    p[2] = 'c';
      33    __analyzer_eval (p[0] == 'a'); /* { dg-warning "TRUE" } */
      34    __analyzer_eval (p[1] == 'b'); /* { dg-warning "TRUE" } */
      35    __analyzer_eval (p[2] == 'c'); /* { dg-warning "TRUE" } */
      36  
      37    q = realloc (p, 6);
      38  
      39    /* We should have 3 nodes, corresponding to "failure",
      40       "success without moving", and "success with moving".  */
      41    __analyzer_dump_exploded_nodes (0); /* { dg-warning "3 processed enodes" } */
      42    
      43    if (q)
      44      {
      45        q[3] = 'd';
      46        q[4] = 'e';
      47        q[5] = 'f';
      48        if (q == p)
      49  	{
      50  	  /* "realloc" success, growing the buffer in-place.  */
      51  	  __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */
      52  	  __analyzer_dump_capacity (q); /* { dg-warning "capacity: '\\(\[^\n\r\]*\\)6'" } */
      53  	  __analyzer_eval (q[0] == 'a'); /* { dg-warning "TRUE" } */
      54  	  __analyzer_eval (q[1] == 'b'); /* { dg-warning "TRUE" } */
      55  	  __analyzer_eval (q[2] == 'c'); /* { dg-warning "TRUE" } */
      56  	}
      57        else
      58  	{
      59  	  /* "realloc" success, moving the buffer (and thus freeing "p").  */
      60  	  __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */
      61  	  __analyzer_dump_capacity (q); /* { dg-warning "capacity: '\\(\[^\n\r\]*\\)6'" } */
      62  	  /* We don't know how much of the buffer is copied.  */
      63  	  __analyzer_eval (q[0] == 'a'); /* { dg-warning "UNKNOWN" } */
      64  	  __analyzer_eval (q[1] == 'b'); /* { dg-warning "UNKNOWN" } */
      65  	  __analyzer_eval (q[2] == 'c'); /* { dg-warning "UNKNOWN" } */
      66  	  __analyzer_eval (p[0] == 'a'); /* { dg-warning "UNKNOWN" "unknown" } */
      67  	  /* { dg-warning "use after 'free' of 'p'" "use after free" { target *-*-* } .-1 } */
      68  	}
      69        __analyzer_eval (q[3] == 'd'); /* { dg-warning "TRUE" } */
      70        __analyzer_eval (q[4] == 'e'); /* { dg-warning "TRUE" } */
      71        __analyzer_eval (q[5] == 'f'); /* { dg-warning "TRUE" } */
      72      }
      73    else
      74      {
      75        /* "realloc" failure.  p should be unchanged.  */
      76        __analyzer_dump_exploded_nodes (0); /* { dg-warning "1 processed enode" } */
      77        __analyzer_dump_capacity (q); /* { dg-warning "capacity: 'UNKNOWN\\(\[^\n\r\]*\\)'" } */
      78        __analyzer_eval (p[0] == 'a'); /* { dg-warning "TRUE" } */
      79        __analyzer_eval (p[1] == 'b'); /* { dg-warning "TRUE" } */
      80        __analyzer_eval (p[2] == 'c'); /* { dg-warning "TRUE" } */
      81        return p;
      82      }
      83  
      84    return q;
      85  }