M include/object.h => include/object.h +5 -2
@@ 39,10 39,13 @@ object_isdeallocand(struct object *, struct state *);
struct location;
bool
-object_references(struct object *, struct location *, struct state *);
+object_references(struct object *, struct location *, struct state *,
+ struct circuitbreaker *);
+
+struct circuitbreaker;
bool
-object_referencesheap(struct object *, struct state *);
+object_referencesheap(struct object *, struct state *, struct circuitbreaker *);
bool
object_hasvalue(struct object *);
M include/state.h => include/state.h +8 -2
@@ 147,10 147,16 @@ char *
location_str(struct location *);
bool
-location_references(struct location *l1, struct location *l2, struct state *);
+location_references(struct location *l1, struct location *l2, struct state *,
+ struct circuitbreaker *cb);
+
+struct circuitbreaker;
+
+struct circuitbreaker;
bool
-location_referencesheap(struct location *, struct state *);
+location_referencesheap(struct location *, struct state *,
+ struct circuitbreaker *);
struct value *
location_transfigure(struct location *, struct state *compare);
M include/util.h => include/util.h +15 -0
@@ 115,4 115,19 @@ error_get_undecideable_cond(struct error *);
char *
error_str(struct error *);
+
+struct circuitbreaker;
+
+struct circuitbreaker *
+circuitbreaker_create();
+
+struct circuitbreaker *
+circuitbreaker_copy(struct circuitbreaker *);
+
+void
+circuitbreaker_destroy(struct circuitbreaker *);
+
+bool
+circuitbreaker_append(struct circuitbreaker *, void *);
+
#endif
M include/value.h => include/value.h +5 -2
@@ 86,8 86,10 @@ value_islocation(struct value *);
struct location *
value_as_location(struct value *);
+struct circuitbreaker;
+
bool
-value_referencesheap(struct value *, struct state *);
+value_referencesheap(struct value *, struct state *, struct circuitbreaker *);
bool
value_isconstant(struct value *v);
@@ 111,7 113,8 @@ struct ast_expr *
value_as_literal(struct value *v);
bool
-value_references(struct value *, struct location *, struct state *);
+value_references(struct value *, struct location *, struct state *,
+ struct circuitbreaker *);
enum ast_binary_operator;
M src/object/object.c => src/object/object.c +26 -8
@@ 28,7 28,8 @@ bool
range_isdeallocand(struct range *, struct state *);
bool
-range_references(struct range *, struct location *, struct state *);
+range_references(struct range *, struct location *, struct state *,
+ struct circuitbreaker *cb);
struct object {
@@ 152,13 153,21 @@ inner_str(struct object *obj)
}
bool
-object_referencesheap(struct object *obj, struct state *s)
+object_referencesheap(struct object *obj, struct state *s,
+ struct circuitbreaker *cb)
{
+ if (!circuitbreaker_append(cb, obj)) {
+ /* already analysed */
+ return false;
+ }
if (!object_isvalue(obj)) {
/* TODO: do we need to exclude the case of ranges on stack? */
return true;
}
- return obj->value && value_referencesheap(obj->value, s);
+ struct circuitbreaker *copy = circuitbreaker_copy(cb);
+ bool ans = obj->value && value_referencesheap(obj->value, s, copy);
+ circuitbreaker_destroy(copy);
+ return ans;
}
bool
@@ 198,16 207,24 @@ object_isdeallocand(struct object *obj, struct state *s)
}
bool
-object_references(struct object *obj, struct location *loc, struct state *s)
+object_references(struct object *obj, struct location *loc, struct state *s,
+ struct circuitbreaker *cb)
{
+ if (!circuitbreaker_append(cb, obj)) {
+ /* already handled */
+ return false;
+ }
if (obj->type == OBJECT_DEALLOCAND_RANGE) {
- return range_references(obj->range, loc, s);
+ return range_references(obj->range, loc, s, cb);
}
assert(obj->type == OBJECT_VALUE);
+ struct circuitbreaker *copy = circuitbreaker_copy(cb);
struct value *v = object_as_value(obj);
- return v ? value_references(v, loc, s) : false;
+ bool ans = v ? value_references(v, loc, s, copy) : false;
+ circuitbreaker_destroy(copy);
+ return ans;
}
struct error *
@@ 588,9 605,10 @@ range_isdeallocand(struct range *r, struct state *s)
}
bool
-range_references(struct range *r, struct location *loc, struct state *s)
+range_references(struct range *r, struct location *loc, struct state *s,
+ struct circuitbreaker *cb)
{
- return location_references(r->loc, loc, s);
+ return location_references(r->loc, loc, s, cb);
}
M src/state/block.c => src/state/block.c +6 -3
@@ 116,12 116,13 @@ block_observe(struct block *b, struct ast_expr *offset, struct state *s,
}
bool
-block_references(struct block *b, struct location *loc, struct state *s)
+block_references(struct block *b, struct location *loc, struct state *s,
+ struct circuitbreaker *cb)
{
int n = object_arr_nobjects(b->arr);
struct object **obj = object_arr_objects(b->arr);
for (int i = 0; i < n; i++) {
- if (object_references(obj[i], loc, s)) {
+ if (object_references(obj[i], loc, s, cb)) {
return true;
}
}
@@ 273,9 274,11 @@ block_undeclare(struct block *b, struct state *s)
struct object **object = object_arr_objects(b->arr);
for (int i = 0; i < n; i++) {
struct object *obj = object[i];
- if (object_referencesheap(obj, s)) {
+ struct circuitbreaker *cb = circuitbreaker_create();
+ if (object_referencesheap(obj, s, cb)) {
object_arr_append(new, object_abstractcopy(obj, s));
}
+ circuitbreaker_destroy(cb);
}
object_arr_destroy(b->arr);
M src/state/block.h => src/state/block.h +4 -1
@@ 31,8 31,11 @@ block_observe(struct block *, struct ast_expr *offset, struct state *,
struct location;
+struct circuitbreaker;
+
bool
-block_references(struct block *, struct location *, struct state *);
+block_references(struct block *, struct location *, struct state *,
+ struct circuitbreaker *);
struct error *
block_range_alloc(struct block *b, struct ast_expr *lw, struct ast_expr *up,
M src/state/location.c => src/state/location.c +5 -4
@@ 251,14 251,15 @@ location_equal(struct location *l1, struct location *l2)
}
bool
-location_references(struct location *l1, struct location *l2, struct state *s)
+location_references(struct location *l1, struct location *l2, struct state *s,
+ struct circuitbreaker *cb)
{
if (location_equal(l1, l2)) {
return true;
}
struct block *b = state_getblock(s, l1);
- return b && block_references(b, l2, s);
+ return b && block_references(b, l2, s, cb);
}
bool
@@ 268,7 269,7 @@ location_isauto(struct location *loc)
}
bool
-location_referencesheap(struct location *l, struct state *s)
+location_referencesheap(struct location *l, struct state *s, struct circuitbreaker *cb)
{
if (l->type == LOCATION_DYNAMIC) {
if (heap_blockisfreed(state_getheap(s), l->block)) {
@@ 280,7 281,7 @@ location_referencesheap(struct location *l, struct state *s)
if (res.err) {
assert(false);
}
- return res.obj && object_referencesheap(res.obj, s);
+ return res.obj && object_referencesheap(res.obj, s, cb);
}
static struct block_res
M src/state/location.h => src/state/location.h +3 -2
@@ 72,7 72,7 @@ bool
location_toclump(struct location *, struct clump *);
bool
-location_referencesheap(struct location *, struct state *);
+location_referencesheap(struct location *, struct state *, struct circuitbreaker *);
enum location_type
location_type(struct location *loc);
@@ 91,7 91,8 @@ bool
location_equal(struct location *loc1, struct location *loc2);
bool
-location_references(struct location *loc1, struct location *loc2, struct state *);
+location_references(struct location *loc1, struct location *loc2, struct state *,
+ struct circuitbreaker *cb);
struct static_memory;
M src/state/stack.c => src/state/stack.c +4 -1
@@ 403,7 403,10 @@ variable_references(struct variable *v, struct location *loc, struct state *s)
{
assert(location_type(loc) != LOCATION_VCONST);
- return location_references(v->loc, loc, s);
+ struct circuitbreaker *cb = circuitbreaker_create();
+ bool ans = location_references(v->loc, loc, s, cb);
+ circuitbreaker_destroy(cb);
+ return ans;
}
bool
M src/util/util.c => src/util/util.c +43 -0
@@ 428,3 428,46 @@ error_str(struct error *err)
assert(false);
}
}
+
+struct circuitbreaker {
+ int n;
+ void **obj;
+};
+
+struct circuitbreaker *
+circuitbreaker_create()
+{
+ return calloc(1, sizeof(struct circuitbreaker));
+}
+
+struct circuitbreaker *
+circuitbreaker_copy(struct circuitbreaker *old)
+{
+ struct circuitbreaker *new = malloc(sizeof(struct circuitbreaker));
+ new->n = old->n;
+ new->obj = malloc(sizeof(void *) * old->n);
+ for (int i = 0; i < old->n; i++) {
+ new->obj[i] = old->obj[i];
+ }
+ return new;
+}
+
+void
+circuitbreaker_destroy(struct circuitbreaker *cb)
+{
+ free(cb);
+}
+
+bool
+circuitbreaker_append(struct circuitbreaker *cb, void *obj)
+{
+ for (int i = 0; i < cb->n; i++) {
+ if (cb->obj[i] == obj) {
+ return false;
+ }
+ }
+ cb->obj = realloc(cb->obj, sizeof(void *) * ++cb->n);
+ assert(cb->obj);
+ cb->obj[cb->n-1] = obj;
+ return true;
+}
M src/value/value.c => src/value/value.c +32 -16
@@ 57,10 57,10 @@ value_ptr_indefinite_create()
return v;
}
-static bool
-ptr_referencesheap(struct value *v, struct state *s)
+bool
+ptr_referencesheap(struct value *v, struct state *s, struct circuitbreaker *cb)
{
- return !v->ptr.isindefinite && location_referencesheap(v->ptr.loc, s);
+ return !v->ptr.isindefinite && location_referencesheap(v->ptr.loc, s, cb);
}
struct number *
@@ 423,13 423,13 @@ value_struct_member(struct value *v, char *member)
return map_get(v->_struct.m, member);
}
-static bool
-struct_referencesheap(struct value *v, struct state *s)
+bool
+struct_referencesheap(struct value *v, struct state *s, struct circuitbreaker *cb)
{
struct map *m = v->_struct.m;
for (int i = 0; i < m->n; i++) {
struct value *val = object_as_value((struct object *) m->entry[i].value);
- if (val && value_referencesheap(val, s)) {
+ if (val && value_referencesheap(val, s, cb)) {
return true;
}
}
@@ 490,10 490,14 @@ value_copy(struct value *v)
}
}
+static bool
+referencesheap_withcb(struct value *, struct state *);
+
+
struct value *
value_abstractcopy(struct value *v, struct state *s)
{
- if (!value_referencesheap(v, s)) {
+ if (!referencesheap_withcb(v, s)) {
return NULL;
}
switch (v->type) {
@@ 506,6 510,15 @@ value_abstractcopy(struct value *v, struct state *s)
}
}
+static bool
+referencesheap_withcb(struct value *v, struct state *s)
+{
+ struct circuitbreaker *cb = circuitbreaker_create();
+ bool ans = value_referencesheap(v, s, cb);
+ circuitbreaker_destroy(cb);
+ return ans;
+}
+
void
value_destroy(struct value *v)
{
@@ 580,13 593,13 @@ value_as_location(struct value *v)
}
bool
-value_referencesheap(struct value *v, struct state *s)
+value_referencesheap(struct value *v, struct state *s, struct circuitbreaker *cb)
{
switch (v->type) {
case VALUE_PTR:
- return ptr_referencesheap(v, s);
+ return ptr_referencesheap(v, s, cb);
case VALUE_STRUCT:
- return struct_referencesheap(v, s);
+ return struct_referencesheap(v, s, cb);
default:
return false;
}
@@ 684,16 697,18 @@ value_type(struct value *v)
}
static bool
-struct_references(struct value *v, struct location *loc, struct state *s);
+struct_references(struct value *v, struct location *loc, struct state *s,
+ struct circuitbreaker *);
bool
-value_references(struct value *v, struct location *loc, struct state *s)
+value_references(struct value *v, struct location *loc, struct state *s,
+ struct circuitbreaker *cb)
{
switch (v->type) {
case VALUE_PTR:
- return !v->ptr.isindefinite && location_references(v->ptr.loc, loc, s);
+ return !v->ptr.isindefinite && location_references(v->ptr.loc, loc, s, cb);
case VALUE_STRUCT:
- return struct_references(v, loc, s);
+ return struct_references(v, loc, s, cb);
default:
/* other kinds of values cannot reference */
return false;
@@ 701,14 716,15 @@ value_references(struct value *v, struct location *loc, struct state *s)
}
static bool
-struct_references(struct value *v, struct location *loc, struct state *s)
+struct_references(struct value *v, struct location *loc, struct state *s,
+ struct circuitbreaker *cb)
{
struct map *m = v->_struct.m;
for (int i = 0; i < m->n; i++) {
struct value *val = object_as_value(
(struct object *) m->entry[i].value
);
- if (val && value_references(val, loc, s)) {
+ if (val && value_references(val, loc, s, cb)) {
return true;
}
}
A tests/0-basic/300-FAIL-with-recursive-struct.x => tests/0-basic/300-FAIL-with-recursive-struct.x +26 -0
@@ 0,0 1,26 @@
+/*
+ * thanks to jorendorff
+ * https://github.com/xr0-org/xr0/issues/46
+ */
+
+#include <stdlib.h>
+
+struct node {
+ struct node *next;
+};
+
+struct node *
+f() ~ [
+ struct node *one;
+
+ one = malloc(sizeof(struct node));
+ one->next = one;
+ return one;
+]{
+ struct node *one;
+
+ one = malloc(sizeof(struct node));
+ one->next = one;
+ malloc(1);
+ return one;
+}
A tests/0-basic/300-FAIL-with-recursive-struct.x.EXPECTED => tests/0-basic/300-FAIL-with-recursive-struct.x.EXPECTED +1 -0
@@ 0,0 1,1 @@
+f: garbage on heap
A tests/0-basic/301-FAIL-with-recursive-struct.x => tests/0-basic/301-FAIL-with-recursive-struct.x +24 -0
@@ 0,0 1,24 @@
+/*
+ * thanks to jorendorff
+ * https://github.com/xr0-org/xr0/issues/46
+ */
+
+#include <stdlib.h>
+
+struct node {
+ struct node *next;
+};
+
+struct node *
+f() ~ [
+ struct node one;
+
+ one.next = &one;
+ return &one;
+]{
+ struct node one;
+
+ one.next = &one;
+ malloc(1);
+ return &one;
+}
A tests/0-basic/301-FAIL-with-recursive-struct.x.EXPECTED => tests/0-basic/301-FAIL-with-recursive-struct.x.EXPECTED +1 -0
@@ 0,0 1,1 @@
+f: garbage on heap