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