Commit 432e7077 authored by Sergio Costas's avatar Sergio Costas

Now checks that crust memory blocks have been freed fine at the end of a function

parent a9b711f3
......@@ -459,6 +459,8 @@ class crusty(object):
return [ (self.STATUS_NULL, self._copy_container(var_container), self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE) ]
elif status == self.STATUS_NULL:
return [ (self.STATUS_NOT_NULL, self._copy_container(var_container), self.TYPE_NO_CRUST,None, crusty.CONDITION_TRUE) ]
elif (status == self.STATUS_FREED) or (status == self.STATUS_UNINITIALIZED):
return [ (status, self._copy_container(var_container), self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE_TRUE) ]
else: # (varname.status == self.STATUS_NOT_NULL_OR_NULL) or (varname.status == self.STATUS_GLOBAL):
var1 = self._copy_container(var_container)
var2 = self._copy_container(var_container)
......@@ -470,6 +472,8 @@ class crusty(object):
return [ (self.STATUS_NOT_NULL, self._copy_container(var_container), self.TYPE_NO_CRUST,None, crusty.CONDITION_TRUE) ]
elif status == self.STATUS_NULL:
return [ (self.STATUS_NULL, self._copy_container(var_container), self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE) ]
elif (status == self.STATUS_FREED) or (status == self.STATUS_UNINITIALIZED):
return [ (status, self._copy_container(var_container), self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE_TRUE) ]
else: # (varname.status == self.STATUS_NOT_NULL_OR_NULL) or (varname.status == self.STATUS_GLOBAL):
var1 = self._copy_container(var_container)
var2 = self._copy_container(var_container)
......@@ -497,6 +501,11 @@ class crusty(object):
for op2 in op2list:
if (op1[0] == self.STATUS_NULL) and (op2[0] == self.STATUS_NULL):
retvals += [(self.STATUS_NULL, op2[1], self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE) ]
elif ((op1[0] == self.STATUS_FREED) or
(op2[0] == self.STATUS_FREED) or
(op1[0] == self.STATUS_UNINITIALIZED) or
(op2[0] == self.STATUS_UNINITIALIZED)):
retvals += [(self.STATUS_UNINITIALIZED, op2[1], self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE_TRUE) ]
else:
retvals += [ (self.STATUS_NOT_NULL, op2[1], self.TYPE_NO_CRUST,None, crusty.CONDITION_TRUE), (self.STATUS_NULL, op2[1], self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE) ]
return retvals
......@@ -530,7 +539,14 @@ class crusty(object):
for op1 in op1list:
op2list = self._eval_assignment(assignment.child2[0],op1[1],True)
for op2 in op2list:
retvals += [(self.STATUS_NOT_NULL_OR_NULL, op2[1], self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE_TRUE) ]
if ((op1[0] == self.STATUS_FREED) or
(op2[0] == self.STATUS_FREED) or
(op1[0] == self.STATUS_UNINITIALIZED) or
(op2[0] == self.STATUS_UNINITIALIZED)):
new_status = self.STATUS_UNINITIALIZED
else:
new_status = self.STATUS_NOT_NULL_OR_NULL
retvals += [(new_status, op2[1], self.TYPE_NO_CRUST,None, crusty.CONDITION_FALSE_TRUE) ]
return retvals
if assignment.type == "!":
......@@ -589,7 +605,10 @@ class crusty(object):
self._add_error(self.MSG_CRITICAL,"Return value for function '{:s}', defined at line {:d}, is defined as __crust_t__ type, but it is not a pointer",node.name,node.line)
else:
self._add_error(self.MSG_CRITICAL,"Variable '{:s}' is defined as __crust_t__ type at line {:d}, but it is not a pointer",node.name,node.line)
retval["crust"] = True
elif node.pointer == 1:
retval["crust"] = True
else:
retval["crust"] = False
if (node.t_crusty_borrow or node.t_crusty_recycle):
if not is_parameter:
self._add_error(self.MSG_CRITICAL,"Variable '{:s}', defined at line {:d}, have __crust_ modifiers other than __crust_t__",node.name,node.line)
......@@ -696,6 +715,8 @@ class crusty(object):
def _process_block(self, tree, var_container):
if tree[0].type == "START_BLOCK":
tree = tree[1:] # the variable block has been already added
blocks = [ (tree,var_container) ]
while len(blocks) > 0:
current_block = blocks[0]
......@@ -726,8 +747,20 @@ class crusty(object):
var_container.insert(0,{})
return self._check_return_block(tree[1:],var_container)
if node.type == "END_BLOCK":
current_block = var_container[0]
# remove the last block of variables
var_container = var_container[1:]
# check if there are memory blocks in use
for variable in current_block:
data = current_block[variable]
if not data["crust"]:
continue
init_line = data["init_line"]
if ((data["status"] == self.STATUS_NOT_NULL) or (data["status"] == self.STATUS_NOT_NULL_OR_NULL)) and (not data["borrowed"]):
if init_line is None:
self._add_error(self.MSG_ERROR,"Memory block '{:s}' still is in use at exit point at line {:d}",variable,node.line)
else:
self._add_error(self.MSG_ERROR,"Memory block '{:s}', initialized at line {:d}, still is in use at exit point at line {:d}",variable,init_line,node.line)
return self._check_return_block(tree[1:],var_container)
if node.type == "EMPTY_DECLARATOR":
return self._check_return_block(tree[1:],var_container)
......
......@@ -172,14 +172,20 @@ void append_right(struct AST *leaf, struct AST *right) {
}
void append_next(struct AST *leaf, struct AST *next) {
int last_line;
while (leaf->next != NULL) {
last_line = leaf->line;
leaf = leaf->next;
}
leaf->next = next;
if ((next->type == END_BLOCK) && (next->line == -1)) {
next->line = last_line;
}
}
void append_next_leaf(struct AST *leaf,int type_leaf) {
void append_next_leaf(struct AST *leaf,int type_leaf, int line) {
struct AST *leaf2 = new_leaf(type_leaf,NULL);
leaf2->line = line;
append_next(leaf,leaf2);
}
......
......@@ -90,7 +90,7 @@ struct AST * new_leaf(int type, struct AST *template);
struct AST * new_leaf_char(int type, char *data);
void append_right(struct AST *leaf, struct AST *right);
void append_next(struct AST *leaf, struct AST *next);
void append_next_leaf(struct AST *leaf,int type_leaf);
void append_next_leaf(struct AST *leaf,int type_leaf, int line);
void append_fparams(struct AST *leaf, struct AST *param);
void mix_ast_leaves(struct AST *base, struct AST *new_leaf);
void copy_ast_data(struct AST *base, struct AST *new_leaf);
......
......@@ -701,12 +701,13 @@ labeled_statement
;
compound_statement
: '{' '}' { $$ = new_leaf(EMPTY_DECLARATOR,$1);
: '{' '}' { $$ = new_leaf(START_BLOCK,$1);
append_next_leaf($$,END_BLOCK,$2->line);
free_tree($1);
free_tree($2); }
| '{' block_item_list '}' { $$ = new_leaf(START_BLOCK,$1);
append_next($$, $2);
append_next_leaf($$,END_BLOCK);
append_next_leaf($$,END_BLOCK,$3->line);
free_tree($1);
free_tree($3); }
;
......@@ -739,9 +740,9 @@ selection_statement
if ($5->type == START_BLOCK) {
append_next($$,$5);
} else {
append_next_leaf($$,START_BLOCK);
append_next_leaf($$,START_BLOCK,$5->line);
append_next($$, $5);
append_next_leaf($$,END_BLOCK);
append_next_leaf($$,END_BLOCK,-1);
}
free_tree($2);
free_tree($4);
......@@ -751,17 +752,17 @@ selection_statement
if ($5->type == START_BLOCK) {
append_next($$,$5);
} else {
append_next_leaf($$,START_BLOCK);
append_next_leaf($$,START_BLOCK,$5->line);
append_next($$, $5);
append_next_leaf($$,END_BLOCK);
append_next_leaf($$,END_BLOCK,$5->line);
}
append_next($$,$6);
if ($7->type == START_BLOCK) {
append_next($$,$7);
} else {
append_next_leaf($$,START_BLOCK);
append_next_leaf($$,START_BLOCK,$7->line);
append_next($$, $7);
append_next_leaf($$,END_BLOCK);
append_next_leaf($$,END_BLOCK,$7->line);
}
free_tree($2);
free_tree($4);
......@@ -769,7 +770,7 @@ selection_statement
| SWITCH '(' expression ')' statement { $$ = $1;
$$->condition = $3;
append_next($$,$5);
append_next_leaf($$,END_SWITCH);
append_next_leaf($$,END_SWITCH,-1);
free_tree($2);
free_tree($4); }
;
......
......@@ -88,7 +88,7 @@ class Test(unittest.TestCase):
self._generic_test("unitest/test6.c",[ (crusty.crusty.MSG_CRITICAL,"Expected a __crust_t__ variable at parameter {:d} when calling function '{:s}' at line {:d}, but passed non __crust_t__ variable",1,"function",6) ])
def testPassedCrustyToNonCrusty(self):
self._generic_test("unitest/test7.c",[ (crusty.crusty.MSG_CRITICAL,"Expected a non __crust_t__ variable at parameter {:d} when calling function '{:s}' at line {:d}, but passed a __crust_t__ variable",1,"function",6) ])
self._generic_test("unitest/test7.c",[ (crusty.crusty.MSG_CRITICAL,"Expected a non __crust_t__ variable at parameter {:d} when calling function '{:s}' at line {:d}, but passed a __crust_t__ variable",1,"function",10) ])
def testPassedOtherToCrusty(self):
self._generic_test("unitest/test8.c",[ (crusty.crusty.MSG_CRITICAL,"Expected a __crust_t__ variable at parameter {:d} when calling function '{:s}' at line {:d}",1,"function",5) ])
......@@ -151,7 +151,7 @@ class Test(unittest.TestCase):
self._generic_test("unitest/test27.c",[ (crusty.crusty.MSG_CRITICAL,"Assigning a non-crust value to the crust variable '{:s}' at line {:d}","param",5) ])
def testCrustRetVal(self):
self._generic_test("unitest/test28.c",[ (crusty.crusty.MSG_ERROR,"Calling the function '{:s}' at line {:d}, but ignoring the crust-type return value","function",5) ])
self._generic_test("unitest/test28.c",[ (crusty.crusty.MSG_ERROR,"Calling the function '{:s}' at line {:d}, but ignoring the crust-type return value","function",9) ])
def testUseUninitialized2(self):
self._generic_test("unitest/test29.c",[ (crusty.crusty.MSG_ERROR,"Parameter {:d} when calling function '{:s}' at line {:d} isn't initialized",1,"function",5) ])
......@@ -220,7 +220,7 @@ class Test(unittest.TestCase):
self._check_var_status(lib,"var2",crusty.crusty.STATUS_NULL)
def testPassBorrowToNonBorrow(self):
self._generic_test("unitest/test50.c",[ (crusty.crusty.MSG_CRITICAL,"Parameter '{:s}' at position {:d} when calling function '{:s}' at line {:d} is borrowed, but is used as a non-borrow parameter",'param',1,"test_function",9) ])
self._generic_test("unitest/test50.c",[ (crusty.crusty.MSG_CRITICAL,"Parameter '{:s}' at position {:d} when calling function '{:s}' at line {:d} is borrowed, but is used as a non-borrow parameter",'param',1,"test_function",10) ])
def testPassBorrowToBorrow(self):
self._all_fine_test("unitest/test51.c")
......
......@@ -9,6 +9,10 @@ __crust_t__ unsigned char * calling3() {
}
void calling4(crust_t param) {
calling4(param); // a trick to free param and trigger only one error
}
void main() {
int a = 1 ? 3 : 0;
......@@ -26,4 +30,7 @@ void main() {
param1 = calling2();
param2 = calling3();
calling4(param1); // a trick to free param1 and trigger only one error
calling4(param2); // a trick to free param2 and trigger only one error
calling4(param4); // a trick to free param4 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
void function(crust_t param1) {
crust_t param4;
int retval = (param4 == NULL) ? 1 : 0; // ERROR: conditional depends on an uninitialized variable
function(param1); // a trick to free param1 and trigger only one error
}
......@@ -4,4 +4,5 @@ int function(crust_t param1) {
crust_t param4 = NULL;
int retval = function(param4);
int retval = (param4 == NULL) ? 1 : 0; // ERROR: condition depends on a freed variable
function(param1); // a trick to free param1 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ int * crust_t;
int function(crust_t param1) {
crust_t param4 = param1;
crust_t param5 = param1; // ERROR: assigning a previously freed variable (due to assign in line 4)
function(param4); // a trick to free param4 and trigger only one error
}
......@@ -3,5 +3,7 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
int v = 5;
crust_t *param = (crust_t) v; // This is legal
crust_t param = (crust_t) v; // This is legal
function(param3); // a trick to free param3 and trigger only one error
function(param); // a trick to free param and trigger only one error
}
typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
int function(crust_t param1) {
crust_t *param = 5; // ERROR: assigning a constant (non-crust) to a crust variable
crust_t param = 5; // ERROR: assigning a constant (non-crust) to a crust variable
function(param1); // a trick to free param1 and trigger only one error
function(param); // a trick to free param and trigger only one error
}
typedef __crust_t__ unsigned char *crust_t;
void function2(crust_t param3) {
function2(param3); // a trick to free param3 and trigger only one error
}
crust_t function(crust_t param3) {
function(NULL); // ERROR: the function returns a crust_t pointer, but it isn't stored
function2(param3); // a trick to free param3 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
crust_t param4;
function(param4); // ERROR: calling a function with an uninitialized parameter
function(param3); // a trick to free param3 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param1, crust_t param2) {
crust_t param3 = param1;
param3 = param2; // ERROR: param3 is overwriten by another variable without being NULL
function(param3,NULL);
}
......@@ -4,4 +4,5 @@ int function(crust_t param3) {
int *param = 1;
function(param); // ERROR: calling a function passing a non-crust value as a crust parameter
function(param3); // a trick to free param3 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
function(2); // ERROR: calling a function passing a constant (non-crust) value as a crust parameter
function(param3); // a trick to free param3 and trigger only one error
}
typedef __crust_t__ unsigned char *crust_t;
void main() {
void main(crust_t param1) {
crust_t a,b;
a = b = 5; // ERROR: assigning a non-crust value to two crust variables
main(param1); // a trick to free param1 and trigger only one error
main(a); // a trick to free a and trigger only one error
main(b); // a trick to free b and trigger only one error
}
......@@ -6,4 +6,6 @@ struct {
int function(crust_t param3) {
crust_t param4 = test.value; // this is legal
function(param3); // a trick to free param3 and trigger only one error
function(param4); // a trick to free param4 and trigger only one error
}
......@@ -6,4 +6,6 @@ struct {
int function(crust_t param3) {
crust_t param4 = test; // ERROR: assigning a non-crust variable into a crust variable
function(param3); // a trick to free param3 and trigger only one error
function(param4); // a trick to free param4 and trigger only one error
}
......@@ -2,6 +2,8 @@ typedef __crust_t__ unsigned char *crust_t;
crust_t test[5];
int function(crust_t param3) {
int function(crust_t param1) {
crust_t param4 = test[1]; // this is legal
function(param1); // a trick to free param1 and trigger only one error
function(param4); // a trick to free param4 and trigger only one error
}
......@@ -2,6 +2,8 @@ typedef __crust_t__ unsigned char *crust_t;
crust_t test[5];
int function(crust_t param3) {
int function(crust_t param1) {
crust_t param4 = test; // ERROR: it is an array, not a crust_t element
function(param1); // a trick to free param1 and trigger only one error
function(param4); // a trick to free param4 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
crust_t param4;
int retval = function(param4); // ERROR: param4 is used before being assigned
function(param3); // a trick to free param3 and trigger only one error
}
......@@ -6,4 +6,6 @@ struct {
int function(crust_t param3) {
crust_t param4 = test->value; // this is legal
function(param3); // a trick to free param3 and trigger only one error
function(param4); // a trick to free param4 and trigger only one error
}
......@@ -8,5 +8,8 @@ void main(crust_t param) {
if (param == NULL) {
param = var2;
} else {
main(var2); // a trick to free var2 and trigger only one error
}
main(param); // a trick to free param and trigger only one error
}
......@@ -9,4 +9,5 @@ void main(crust_t param) {
main(param);
}
param = var2;
main(param); // a trick to free param and trigger only one error
}
......@@ -7,7 +7,9 @@ void main(crust_t param) {
crust_t var2 = (crust_t) 5;
if (param != NULL) {
main(param);
main(var2); // a trick to free var2 and trigger only one error
} else {
param = var2;
main(param);
}
}
......@@ -2,10 +2,16 @@ typedef __crust_t__ unsigned char *crust_t;
#define NULL ((void *)0)
void function(crust_t param) {
function(param); // a trick to free param and trigger only one error
}
crust_t main(crust_t __crust_recycle__ param) {
crust_t var2 = (crust_t) 5;
crust_t var3;
var3 = main(var2); // This is legal
__crust_debug__
function(param); // a trick to free param and trigger only one error
function(var3); // a trick to free var3 and trigger only one error
}
typedef __crust_t__ unsigned char *crust_t;
#define NULL ((void *)0)
int function(crust_t param1) {
function(param1); // a trick to free param1 and trigger only one error
}
void main(crust_t __crust_borrow__ param) {
crust_t var2 = (crust_t) 5;
main(var2); // This is legal
__crust_debug__
function(var2); // a trick to free var2 and trigger only one error
}
......@@ -3,6 +3,7 @@ typedef __crust_t__ unsigned char *crust_t;
#define NULL ((void *)0)
void test_function(crust_t param) {
test_function(param); // a trick to free param and trigger only one error
}
void main(crust_t __crust_borrow__ param) {
......
......@@ -4,4 +4,5 @@ int function(crust_t param3) {
int *param = 1;
int retval = function(param); // ERROR: passed non-crust variable as a crust parameter
function(param3); // a trick to free param3 and trigger only one error
}
......@@ -7,7 +7,9 @@ void main(crust_t param) {
crust_t var2 = (crust_t) 5;
if (!(param != NULL)) {
param = var2;
main(param);
} else {
main(param);
main(var2); // a trick to free var2 and trigger only one error
}
}
......@@ -7,5 +7,8 @@ void main(crust_t param) {
crust_t var2 = (crust_t) 5;
if (!(param == NULL)) {
param = var2;
} else {
main(var2); // a trick to free var2 and trigger only one error
}
main(param); // a trick to free param and trigger only one error
}
typedef __crust_t__ unsigned char *crust_t;
void function2(crust_t param3) {
function2(param3); // a trick to free param3 and trigger only one error
}
crust_t function(int param3) {
crust_t param = NULL;
crust_t retval = function(param); // ERROR: passed a crust variable to a non-crust param
function2(retval); // a trick to free retval and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
int retval = function(2); // ERROR: passed a constant (non-crust) as a crust parameter
function(param3); // a trick to free param3 and trigger only one error
}
......@@ -3,4 +3,5 @@ typedef __crust_t__ unsigned char *crust_t;
int function(crust_t param3) {
int retval = function(3,5); // ERROR: incorrect number of parameters
function(param3); // a trick to free param3 and trigger only one error
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment