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