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 of 'obj'" "" { xfail *-*-* } } */
79 /* TODO(xfail): the false leak report involves the base_obj.ob_refcnt
80 being 1, but the string_obj.str_base.ob_refcnt being unknown (when
81 they ought to be the same region), thus allowing for a path in which
82 the object is allocated but not freed. */
83
84