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