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