~lbnz/xr0

08065d977a9c989b0f015f638d076ff1de7b2a78 — Amisi Kiarie a month ago 93d3060
fix: overspecificity in state view giving false negatives

issue: https://github.com/xr0-org/xr0/issues/53
M include/object.h => include/object.h +14 -1
@@ 19,6 19,20 @@ object_copy(struct object *old);
struct object *
object_abstractcopy(struct object *old, struct state *s);

struct int_arr;

struct circuitbreaker;

struct state;

struct int_arr *
object_deriveorder(struct object *, struct circuitbreaker *, struct state *);

struct permutation;

struct object *
object_permuteheaplocs(struct object *, struct permutation *);

void
object_destroy(struct object *);



@@ 42,7 56,6 @@ bool
object_references(struct object *, struct location *, struct state *,
		struct circuitbreaker *);

struct circuitbreaker;

bool
object_referencesheap(struct object *, struct state *, struct circuitbreaker *);

M include/state.h => include/state.h +8 -1
@@ 239,6 239,14 @@ location_referencesheap(struct location *, struct state *,
struct value *
location_transfigure(struct location *, struct state *compare);

struct int_arr *
location_deriveorder(struct location *, struct circuitbreaker *, struct state *);

struct permutation;

struct location *
location_permuteheap(struct location *loc, struct permutation *p);

struct object_res {
	struct object *obj;
	struct error *err;


@@ 247,7 255,6 @@ struct object_res {
struct object_res
state_get(struct state *state, struct location *loc, bool constructive);


/* USED BY OBJECT */

bool

M include/util.h => include/util.h +20 -4
@@ 39,10 39,7 @@ map_set(struct map *, const char *key, const void *value);

/* XXX: string_arr: to be macro */

struct string_arr {
	int n;
	char **s;
};
struct string_arr;

struct string_arr *
string_arr_create();


@@ 71,6 68,25 @@ string_arr_contains(struct string_arr *, char *s);
char *
string_arr_str(struct string_arr *);

struct int_arr;

struct int_arr *
int_arr_create();

void
int_arr_destroy();

int *
int_arr_arr(struct int_arr *);

int
int_arr_len(struct int_arr *);

void
int_arr_append(struct int_arr *, int);

void
int_arr_appendrange(struct int_arr *arr, struct int_arr *arr2);

struct strbuilder;


M include/value.h => include/value.h +10 -0
@@ 15,6 15,16 @@ struct value;

struct location;

struct permutation;

struct int_arr;

struct int_arr *
value_deriveorder(struct value *, struct circuitbreaker *, struct state *);

struct value *
value_permuteheaplocs(struct value *, struct permutation *);

struct value *
value_ptr_create(struct location *loc);


M src/ast/topological.c => src/ast/topological.c +5 -5
@@ 26,7 26,7 @@ topological_order(char *fname, struct externals *ext)
	struct map *indegrees = calculate_indegrees(g);
	struct string_arr *indegree_zero = build_indegree_zero(indegrees);
	/* while there are nodes of indegree zero */
	while (indegree_zero->n > 0) {
	while (string_arr_n(indegree_zero) > 0) {
		/* add one node with indegree zero to ordered */
		char *curr = string_arr_deque(indegree_zero);
		string_arr_append(order, curr);


@@ 46,7 46,7 @@ topological_order(char *fname, struct externals *ext)
	}

	/* no more nodes with incoming edges */
	if (order->n != indegrees->n) {
	if (string_arr_n(order) != indegrees->n) {
		/* TODO: pass up error */
		fprintf(stderr, "cycle detected in graph\n");
		exit(EXIT_FAILURE);


@@ 71,8 71,8 @@ calculate_indegrees(struct map *g)
			continue;
		}
		map_set(indegrees, dynamic_str(e.key), dynamic_int(0));
		for (int j = 0; j < deps->n; j++) {
			char *dep_key = deps->s[j]; 
		for (int j = 0; j < string_arr_n(deps); j++) {
			char *dep_key = string_arr_s(deps)[j]; 
			if (map_get(indegrees, dep_key) != NULL) {
				continue;
			}		


@@ 86,7 86,7 @@ calculate_indegrees(struct map *g)
		if (!n_arr) {
			continue;
		}
		for (int j = 0; j < n_arr->n; j++) {
		for (int j = 0; j < string_arr_n(n_arr); j++) {
			int *count = (int *) map_get(indegrees, e.key);
			*count = *count + 1; /* XXX */
		}

M src/object/object.c => src/object/object.c +60 -7
@@ 9,28 9,33 @@
#include "util.h"
#include "value.h"

struct range *
static struct range *
range_copy(struct range *);

void
static void
range_destroy(struct range *);

char *
static char *
range_str(struct range *);

struct ast_expr *
static struct ast_expr *
range_size(struct range *);

struct error *
static struct error *
range_dealloc(struct range *r, struct state *s);

bool
static bool
range_isdeallocand(struct range *, struct state *);

bool
static bool
range_references(struct range *, struct location *, struct state *,
		struct circuitbreaker *cb);

static struct range * 
range_permuteheaplocs(struct range *, struct permutation *);

static struct int_arr *
range_deriveorder(struct range *, struct circuitbreaker *, struct state *);

struct object {
	enum object_type {


@@ 66,6 71,42 @@ object_range_create(struct ast_expr *offset, struct range *r)
	return obj;
}

struct int_arr *
object_deriveorder(struct object *obj, struct circuitbreaker *cb, struct state *s)
{
	switch (obj->type) {
	case OBJECT_VALUE:
		return obj->value
			? value_deriveorder(obj->value, cb, s)
			: int_arr_create();
	case OBJECT_DEALLOCAND_RANGE:
		return range_deriveorder(obj->range, cb, s);
	default:
		assert(false);
	}
}

struct object *
object_permuteheaplocs(struct object *old, struct permutation *p)
{
	struct object *new = malloc(sizeof(struct object));
	new->offset = ast_expr_copy(old->offset);
	new->type = old->type;
	switch (old->type) {
	case OBJECT_VALUE:
		new->value = old->value
			? value_permuteheaplocs(old->value, p)
			: NULL;
		break;
	case OBJECT_DEALLOCAND_RANGE:
		new->range = range_permuteheaplocs(old->range, p);
		break;
	default:
		assert(false);
	}
	return new;
}

void
object_destroy(struct object *obj)
{


@@ 566,6 607,18 @@ range_copy(struct range *r)
	return range_create(ast_expr_copy(r->size), location_copy(r->loc));
}

static struct range * 
range_permuteheaplocs(struct range *r, struct permutation *p)
{
	assert(false);
}

static struct int_arr *
range_deriveorder(struct range *r, struct circuitbreaker *cb, struct state *s)
{
	assert(false);
}

void
range_destroy(struct range *r)
{

M src/state/block.c => src/state/block.c +84 -0
@@ 39,6 39,21 @@ block_copy(struct block *old)
	return new;
}

struct block *
block_permuteheaplocs(struct block *old, struct permutation *p)
{
	struct block *new = malloc(sizeof(struct block));
	new->arr = object_arr_create();

	struct object **obj = object_arr_objects(old->arr);
	int n = object_arr_nobjects(old->arr);
	for (int i = 0; i < n; i++) {
		object_arr_append(new->arr, object_permuteheaplocs(obj[i], p));
	}

	return new;
}

char *
block_str(struct block *block)
{


@@ 347,3 362,72 @@ block_arr_delete(struct block_arr *arr, int address)
{
	assert(false);
}


struct permutation {
	struct int_arr *arr;
};

struct permutation *
permutation_create(struct int_arr *arr)
{
	struct permutation *p = malloc(sizeof(struct permutation));
	p->arr = arr;
	return p;
}

struct permutation *
permutation_copy(struct permutation *old)
{
	struct permutation *new = malloc(sizeof(struct permutation));
	new->arr = int_arr_create();
	int *old_arr = int_arr_arr(old->arr);
	int old_len = int_arr_len(old->arr);
	for (int i = 0; i < old_len; i++) {
		int_arr_append(new->arr, old_arr[i]);
	}
	return new;
}

void
permutation_destroy(struct permutation *p)
{
	int_arr_destroy(p->arr);
	free(p);
}

int
permutation_apply(struct permutation *p, int i)
{
	assert(i < int_arr_len(p->arr));
	return int_arr_arr(p->arr)[i];
}

int
permutation_applyinverse(struct permutation *p, int i)
{
	int len = int_arr_len(p->arr);
	int *perm = int_arr_arr(p->arr);
	assert(i < len);
	for (int j = 0; j < len; j++) {
		if (perm[j] == i) {
			return j;
		}
	}
	assert(false);
}

char *
permutation_str(struct permutation *p)
{
	int len = int_arr_len(p->arr);
	int *arr = int_arr_arr(p->arr);

	struct strbuilder *b = strbuilder_create();
	strbuilder_printf(b, "[");
	for (int i = 0; i < len; i++) {
		strbuilder_printf(b, "%d->%d%s", i, arr[i], i+1<len ? " " : "");
	}
	strbuilder_printf(b, "]");
	return strbuilder_build(b);
}

M src/state/block.h => src/state/block.h +29 -0
@@ 54,6 54,11 @@ block_range_dealloc(struct block *, struct ast_expr *lw, struct ast_expr *up,
void
block_undeclare(struct block *, struct state *);

struct permutation;

struct block *
block_permuteheaplocs(struct block *, struct permutation *);

struct block_arr;

struct block_arr *


@@ 78,4 83,28 @@ block_arr_append(struct block_arr *, struct block *);
void
block_arr_delete(struct block_arr *, int address);


struct permutation;

struct permutation *
permutation_create(struct int_arr *);

struct permutation *
permutation_inverse_create(struct int_arr *);

struct permutation *
permutation_copy(struct permutation *);

void
permutation_destroy(struct permutation *);

char *
permutation_str(struct permutation *);

int
permutation_apply(struct permutation *, int);

int
permutation_applyinverse(struct permutation *, int);

#endif

M src/state/heap.c => src/state/heap.c +18 -0
@@ 85,6 85,24 @@ printdelim(struct heap *h, int start)
}


struct heap *
heap_permute(struct heap *old, struct permutation *p)
{
	struct heap *new = malloc(sizeof(struct heap));
	int n = block_arr_nblocks(old->blocks);
	struct block **b = block_arr_blocks(old->blocks);
	new->blocks = block_arr_create();
	new->freed = malloc(sizeof(bool) * n);
	for (int i = 0; i < n; i++) {
		int perm_i = permutation_apply(p, i);
		new->freed[i] = old->freed[perm_i];
		block_arr_append(
			new->blocks, block_permuteheaplocs(b[perm_i], p)
		);
	}
	return new;
}

struct block_arr *
heap_blocks(struct heap *h)
{

M src/state/heap.h => src/state/heap.h +10 -0
@@ 17,6 17,16 @@ heap_copy(struct heap *);
char *
heap_str(struct heap *, char *indent);

struct permutation;

struct permutation *
heap_transposezero(struct heap *, int block);

struct heap *
heap_permute(struct heap *, struct permutation *p);

struct location_arr;

struct ast_expr;

struct block_arr *

M src/state/location.c => src/state/location.c +84 -0
@@ 99,6 99,47 @@ location_transfigure(struct location *loc, struct state *compare)
	}
}

struct location *
location_permuteheap(struct location *loc, struct permutation *p)
{
	assert(loc->type == LOCATION_DYNAMIC);
	return location_create_dynamic(
		permutation_applyinverse(p, loc->block), ast_expr_copy(loc->offset)
	);
}

static bool
shouldderiveorder(struct location *, struct circuitbreaker *, struct state *);

struct int_arr *
location_deriveorder(struct location *loc, struct circuitbreaker *cb,
		struct state *s)
{
	struct int_arr *arr = int_arr_create();
	if (shouldderiveorder(loc, cb, s)) {
		if (loc->type == LOCATION_DYNAMIC) {
			int_arr_append(arr, loc->block);
		}
		struct object_res res = state_get(s, loc, false);
		assert(!res.err);
		if (res.obj) {
			int_arr_appendrange(arr, object_deriveorder(res.obj, cb, s));
		}
	}
	return arr;
}

static bool
shouldderiveorder(struct location *loc, struct circuitbreaker *cb,
		struct state *s)
{
	bool onheap_and_freed =
		(loc->type == LOCATION_DYNAMIC
		 && heap_blockisfreed(state_getheap(s), loc->block));

	return circuitbreaker_append(cb, loc) && !onheap_and_freed;
}

void
location_destroy(struct location *loc)
{


@@ 372,3 413,46 @@ location_range_dealloc(struct location *loc, struct ast_expr *lw,

	return block_range_dealloc(b, lw, up, state);
}

struct location_arr {
	int n;
	struct location **loc;
};

struct location_arr *
location_arr_create()
{
	struct location_arr *arr = calloc(1, sizeof(struct location_arr));
	assert(arr);
	return arr;
}

void
location_arr_destroy(struct location_arr *arr)
{
	for (int i = 0; i < arr->n; i++) {
		location_destroy(arr->loc[i]);
	}
	free(arr);
}

struct location **
location_arr_loc(struct location_arr *arr)
{
	return arr->loc;
}

int
location_arr_n(struct location_arr *arr)
{
	return arr->n;
}

void
location_arr_append(struct location_arr *arr, struct location *loc)
{
	arr->loc = realloc(arr->loc, sizeof(struct location *) * ++arr->n);
	assert(arr->loc);
	int n = arr->n-1;
	arr->loc[n] = loc;
}

M src/state/location.h => src/state/location.h +22 -0
@@ 94,6 94,11 @@ bool
location_references(struct location *loc1, struct location *loc2, struct state *,
		struct circuitbreaker *cb);

struct permutation;

struct permutation *
location_heaptransposezero(struct location *, struct heap *); 

struct static_memory;

struct vconst;


@@ 125,4 130,21 @@ struct error *
location_range_dealloc(struct location *loc, struct ast_expr *lw,
		struct ast_expr *up, struct state *);

struct location_arr;

struct location_arr *
location_arr_create();

void
location_arr_destroy();

struct location **
location_arr_loc(struct location_arr *);

int
location_arr_n(struct location_arr *);

void
location_arr_append(struct location_arr *, struct location *);

#endif

M src/state/state.c => src/state/state.c +53 -20
@@ 104,6 104,11 @@ state_str(struct state *state)
		strbuilder_printf(b, "static:\n%s\n", static_mem);
	}
	free(static_mem);
	if (state->reg) {
		char *ret = value_str(state->reg);
		strbuilder_printf(b, "return: <%s>\n\n", ret);
		free(ret);
	}
	char *vconst = vconst_str(state->vconst, "\t");
	if (strlen(vconst) > 0) {
		strbuilder_printf(b, "rconst:\n%s\n", vconst);


@@ 644,37 649,22 @@ state_eval(struct state *s, struct ast_expr *e)
}

static void
state_undeclareliterals(struct state *s);

static void
state_undeclarevars(struct state *s);

static void
state_popprops(struct state *s);

void
state_unnest(struct state *s);
state_normalise(struct state *s);

bool
state_equal(struct state *s1, struct state *s2)
{
	struct state *s1_c = state_copy(s1),
		     *s2_c = state_copy(s2);
	state_unnest(s1_c);
	state_unnest(s2_c);
	state_undeclareliterals(s1_c);
	state_undeclareliterals(s2_c);
	state_undeclarevars(s1_c);
	state_undeclarevars(s2_c);
	state_popprops(s1_c);
	state_popprops(s2_c);
	state_normalise(s1_c);
	state_normalise(s2_c);

	char *str1 = state_str(s1_c),
	     *str2 = state_str(s2_c);
	bool equal = strcmp(str1, str2) == 0;
	if (!equal) {
		v_printf("abstract: %s", str2);
		v_printf("actual: %s", str1);
		v_printf("actual:\n%s", str1);
		v_printf("abstract:\n%s", str2);
	}
	free(str2);
	free(str1);


@@ 686,6 676,49 @@ state_equal(struct state *s1, struct state *s2)
}

static void
state_undeclareliterals(struct state *s);

static void
state_undeclarevars(struct state *s);

static void
state_popprops(struct state *s);

void
state_unnest(struct state *s);

static void
state_permuteheap(struct state *, struct int_arr *);

static void
state_normalise(struct state *s)
{
	state_unnest(s);
	state_undeclareliterals(s);
	state_undeclarevars(s);
	state_popprops(s);
	if (s->reg) {
		struct circuitbreaker *cb = circuitbreaker_create();
		struct int_arr *arr = value_deriveorder(s->reg, cb, s);
		circuitbreaker_destroy(cb);
		state_permuteheap(s, arr);
	}
}


static void
state_permuteheap(struct state *s, struct int_arr *arr)
{
	/* XXX: only permuting heap and return register; clump later */
	assert(s->reg);

	struct permutation *p = permutation_create(arr);
	s->heap = heap_permute(s->heap, p);
	s->reg = value_permuteheaplocs(s->reg, p);
	permutation_destroy(p);
}

static void
state_undeclareliterals(struct state *s)
{
	static_memory_destroy(s->static_memory);

M src/util/util.c => src/util/util.c +58 -2
@@ 189,7 189,10 @@ strbuilder_putc(struct strbuilder *b, char c)
	strbuilder_printf(b, "%c", c);
}

/* string_arr */
struct string_arr {
	int n;
	char **s;
};

struct string_arr *
string_arr_create()


@@ 225,7 228,7 @@ string_arr_n(struct string_arr *arr)
int
string_arr_append(struct string_arr *arr, char *s)
{
	arr->s = realloc(arr->s, sizeof(struct string_arr) * ++arr->n);
	arr->s = realloc(arr->s, sizeof(char *) * ++arr->n);
	assert(arr->s);
	int loc = arr->n-1;
	arr->s[loc] = s;


@@ 288,6 291,59 @@ string_arr_str(struct string_arr *string_arr)
	return strbuilder_build(b);
}


struct int_arr {
	int len;
	int *arr;
};

struct int_arr *
int_arr_create()
{
	struct int_arr *arr = calloc(1, sizeof(struct int_arr));
	assert(arr);
	return arr;
}

void
int_arr_destroy(struct int_arr *arr)
{
	free(arr->arr);
	free(arr);
}

int *
int_arr_arr(struct int_arr *arr)
{
	return arr->arr;
}

int
int_arr_len(struct int_arr *arr)
{
	return arr->len;
}

void
int_arr_append(struct int_arr *arr, int num)
{
	arr->arr = realloc(arr->arr, sizeof(int *) * ++arr->len);
	assert(arr->arr);
	int loc = arr->len-1;
	arr->arr[loc] = num;
}

void
int_arr_appendrange(struct int_arr *arr, struct int_arr *arr2)
{
	int len = int_arr_len(arr2);
	int *arr2_arr = int_arr_arr(arr2);
	for (int i = 0; i < len; i++) {
		int_arr_append(arr, arr2_arr[i]);
	}
}


enum loglevel LOG_LEVEL;

/* d_printf: Print if Xr0 is in debug mode. */

M src/value/value.c => src/value/value.c +92 -0
@@ 32,6 32,53 @@ struct value {
		} _struct;
	};
}; 

static struct int_arr *
struct_deriveorder(struct value *v, struct circuitbreaker *cb, struct state *s);

struct int_arr *
value_deriveorder(struct value *v, struct circuitbreaker *cb, struct state *s)
{
	switch (v->type) {
	case VALUE_SYNC:
	case VALUE_INT:
	case VALUE_LITERAL:
		return int_arr_create();
	case VALUE_PTR:
		if (v->ptr.isindefinite) {
			return int_arr_create();
		}
		return location_deriveorder(v->ptr.loc, cb, s);
	case VALUE_STRUCT:
		return struct_deriveorder(v, cb, s);
	default:
		assert(false);
	}
}

static struct value *
struct_permuteheaplocs(struct value *, struct permutation *);

struct value *
value_permuteheaplocs(struct value *v, struct permutation *p)
{
	switch (v->type) {
	case VALUE_SYNC:
	case VALUE_INT:
	case VALUE_LITERAL:
		return value_copy(v);
	case VALUE_PTR:
		if (v->ptr.isindefinite) {
			return value_copy(v);
		}
		return value_ptr_create(location_permuteheap(v->ptr.loc, p));
	case VALUE_STRUCT:
		return struct_permuteheaplocs(v, p);
	default:
		assert(false);
	}
}

struct value *
value_ptr_create(struct location *loc)
{


@@ 400,6 447,51 @@ copymembers(struct map *old)
	return new;
}


static struct map *
permutemembers(struct map *old, struct permutation *);

static struct value *
struct_permuteheaplocs(struct value *old, struct permutation *p)
{
	struct value *new = malloc(sizeof(struct value));
	assert(new);
	new->type = VALUE_STRUCT;
	new->_struct.members = ast_variable_arr_copy(old->_struct.members);
	new->_struct.m = permutemembers(old->_struct.m, p);
	return new;
}

static struct map *
permutemembers(struct map *old, struct permutation *p)
{
	struct map *new = map_create();
	for (int i = 0; i < old->n; i++) {
		struct entry e = old->entry[i];
		map_set(
			new, dynamic_str(e.key),
			object_permuteheaplocs((struct object *) e.value, p)
		);
	}
	return new;
}

static struct int_arr *
struct_deriveorder(struct value *v, struct circuitbreaker *cb, struct state *s)
{
	struct int_arr *arr = int_arr_create();
	struct map *m = v->_struct.m;
	for (int i = 0; i < m->n; i++) {
		int_arr_appendrange(
			arr,
			object_deriveorder(
				(struct object *) m->entry[i].value, cb, s
			)
		);
	}
	return arr;
}

static struct map *
abstractcopymembers(struct map *old, struct state *s);


A tests/0-basic/400-out-of-order.x => tests/0-basic/400-out-of-order.x +8 -0
@@ 0,0 1,8 @@
#include <stdlib.h>

void
f() ~ [ return malloc(1); ]
{
	free(malloc(1));
	return malloc(1);
}

A tests/0-basic/410-struct-out-of-order.x => tests/0-basic/410-struct-out-of-order.x +25 -0
@@ 0,0 1,25 @@
#include <stdlib.h>

struct pair {
	void *p;
	void *q;
};

struct pair *
f() ~ [
	struct pair *pair;

	pair = malloc(sizeof(struct pair));
	pair->p = malloc(1);
	pair->q = malloc(1);
	return pair;
]{
	struct pair *pair;
	void *q;

	q = malloc(1);
	pair = malloc(sizeof(struct pair));
	pair->p = malloc(1);
	pair->q = q;
	return pair;
}

A tests/0-basic/420-struct-out-of-order.x => tests/0-basic/420-struct-out-of-order.x +21 -0
@@ 0,0 1,21 @@
#include <stdlib.h>

struct pair {
	void *p;
	void *q;
};

struct pair
f() ~ [
	struct pair pair;

	pair.p = malloc(1);
	pair.q = malloc(1);
	return pair;
]{
	struct pair pair;

	pair.q = malloc(1);
	pair.p = malloc(1);
	return pair;
}