(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
analyzer/
data-model-5.c
       1  /* A toy re-implementation of CPython's object model.  */
       2  
       3  #include <stddef.h>
       4  #include <string.h>
       5  #include <stdlib.h>
       6  
       7  typedef struct base_obj
       8  {
       9    struct type_obj *ob_type;
      10    int ob_refcnt;
      11  } base_obj;
      12  
      13  typedef struct type_obj
      14  {
      15    base_obj tp_base;
      16    void (*tp_dealloc) (base_obj *);
      17  } type_obj;
      18  
      19  typedef struct tuple_obj
      20  {
      21    base_obj tup_base;
      22    int num_elements;
      23    base_obj elements[];
      24  } tuple_obj;
      25  
      26  typedef struct list_obj
      27  {
      28    base_obj list_base;
      29    int num_elements;
      30    base_obj *elements;
      31  } list_obj;
      32  
      33  typedef struct string_obj
      34  {
      35    base_obj str_base;
      36    size_t str_len;
      37    char str_buf[];
      38  } string_obj;
      39  
      40  extern void type_del (base_obj *);
      41  extern void tuple_del (base_obj *);
      42  extern void str_del (base_obj *);
      43  
      44  type_obj type_type = {
      45    { &type_type, 1},
      46    type_del
      47  };
      48  
      49  type_obj tuple_type = {
      50    { &type_type, 1},
      51    tuple_del
      52  };
      53  
      54  type_obj str_type = {
      55    { &str_type, 1},
      56    str_del
      57  };
      58  
      59  base_obj *alloc_obj (type_obj *ob_type, size_t sz)
      60  {
      61    base_obj *obj = (base_obj *)malloc (sz);
      62    if (!obj)
      63      return NULL;
      64    obj->ob_type = ob_type;
      65    obj->ob_refcnt = 1;
      66    return obj;
      67  }
      68  
      69  base_obj *new_string_obj (const char *str)
      70  {
      71    //__analyzer_dump ();
      72    size_t len = strlen (str);
      73  #if 1
      74    string_obj *str_obj
      75      = (string_obj *)alloc_obj (&str_type, sizeof (string_obj) + len + 1);
      76  #else
      77    string_obj *str_obj = (string_obj *)malloc (sizeof (string_obj) + len + 1);
      78    if (!str_obj)
      79      return NULL;
      80    str_obj->str_base.ob_type = &str_type;
      81    str_obj->str_base.ob_refcnt = 1;
      82  #endif
      83    str_obj->str_len = len; /* { dg-warning "dereference of NULL 'str_obj'" } */
      84    memcpy (str_obj->str_buf, str, len);
      85    str_obj->str_buf[len] = '\0';
      86    return (base_obj *)str_obj;
      87  }
      88  
      89  void unref (base_obj *obj)
      90  {
      91    if (--obj->ob_refcnt == 0) /* { dg-bogus "dereference of uninitialized pointer 'obj'" } */
      92      obj->ob_type->tp_dealloc (obj);
      93  }
      94  
      95  void test_1 (const char *str)
      96  {
      97    base_obj *obj = new_string_obj (str);
      98    unref (obj);
      99  } /* { dg-bogus "leak" "" { xfail *-*-* } } */
     100  /* XFAIL (false leak):
     101     Given that we only know "len" symbolically, this line:
     102       str_obj->str_buf[len] = '\0';
     103     is a symbolic write which could clobber the ob_type or ob_refcnt.
     104     It reports a leak when following the path where the refcount is clobbered
     105     to be a value that leads to the deallocator not being called.  */