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 
alloc_obj(type_obj * ob_type,size_t sz)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 
new_string_obj(const char * str)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 
unref(string_obj * obj)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 
test_1(const char * str)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 of 'obj'" "" { xfail *-*-* } } */
90 /* TODO(xfail): the false leak report involves the base_obj.ob_refcnt
91    being 1, but the string_obj.str_base.ob_refcnt being unknown (when
92    they ought to be the same region), thus allowing for a path in which
93    the object is allocated but not freed.  */
94