Commit b7b52095 authored by Sergio Costas's avatar Sergio Costas

Now checks when assigning a value to an struct element throug a pointer to...

Now checks when assigning a value to an struct element throug a pointer to that struct, the pointer is valid

Now allows to call functions using pointer to function stored as an element in an struct
parent ad4b6b6a
......@@ -507,27 +507,30 @@ class crust(object):
if orig_data["function"]:
if orig_var.function_params is None:
# we are assigning a function pointer
# here we should compare the type of the function pointer being assigned and the function pointer variable where is
# being stored
# first, check if any of the parameters or return values in both pointers are crust-type
crust_found = False
for param in orig_data["function_params"]:
if param["crust"]:
crust_found = True
for param in dest_data["function_params"]:
if param["crust"]:
crust_found = True
if crust_found:
# we only check if the param types and number are fine if there are crust-type parameters involved
if len(orig_data["function_params"]) != len(dest_data["function_params"]):
self._add_error(v["thread_status"], self.MSG_ERROR, "Trying to assign the function '{:s}' to the function pointer '{:s}' at line {:d}, but they have a different number of parameters", orig_data["name"], dest_data["name"], statement.line)
else:
for c in range(len(orig_data["function_params"])):
if not self._compare_types(orig_data["function_params"][c], dest_data["function_params"][c]):
if c == 0:
self._add_error(v["thread_status"], self.MSG_ERROR, "Trying to assign the function '{:s}' to the function pointer '{:s}' at line {:d}, but the return types differ", orig_data["name"], dest_data["name"], statement.line)
else:
self._add_error(v["thread_status"], self.MSG_ERROR, "Trying to assign the function '{:s}' to the function pointer '{:s}' at line {:d}, but parameter {:d} differs", orig_data["name"], dest_data["name"], statement.line, c)
# here we should compare the type of the function pointer being assigned
# and the function pointer variable where is being stored
# if we are assigning to an struct element, don't compare parameters
if not dest_var.right:
# first, check if any of the parameters or return values in both pointers are crust-type
crust_found = False
for param in orig_data["function_params"]:
if param["crust"]:
crust_found = True
for param in dest_data["function_params"]:
if param["crust"]:
crust_found = True
if crust_found:
# we only check if the param types and number are fine if there are crust-type parameters involved
if len(orig_data["function_params"]) != len(dest_data["function_params"]):
self._add_error(v["thread_status"], self.MSG_ERROR, "Trying to assign the function '{:s}' to the function pointer '{:s}' at line {:d}, but they have a different number of parameters", orig_data["name"], dest_data["name"], statement.line)
else:
for c in range(len(orig_data["function_params"])):
if not self._compare_types(orig_data["function_params"][c], dest_data["function_params"][c]):
if c == 0:
self._add_error(v["thread_status"], self.MSG_ERROR, "Trying to assign the function '{:s}' to the function pointer '{:s}' at line {:d}, but the return types differ", orig_data["name"], dest_data["name"], statement.line)
else:
self._add_error(v["thread_status"], self.MSG_ERROR, "Trying to assign the function '{:s}' to the function pointer '{:s}' at line {:d}, but parameter {:d} differs", orig_data["name"], dest_data["name"], statement.line, c)
else:
# we are assigning the result of a function call
ret_value = orig_data["function_params"][0]
......@@ -549,6 +552,16 @@ class crust(object):
if (orig_type == self.TYPE_NO_CRUST) and (dest_type == self.TYPE_CRUST):
self._add_error(v["thread_status"], self.MSG_CRITICAL, "Assigning a non-crust value to the crust variable '{:s}' at line {:d}", dest_data["name"], statement.line)
if dest_var.right is not None:
if dest_data["value"] == self.VALUE_NULL:
self._add_error(thread_status, self.MSG_ERROR, "Using variable '{:s}' at line {:d} with a NULL value", dest_data["name"], statement.line)
elif dest_data["value"] == self.VALUE_NOT_NULL_OR_NULL:
self._add_error(thread_status, self.MSG_WARNING, "Using variable '{:s}' at line {:d} with a possible NULL value", dest_data["name"], statement.line)
elif dest_data["value"] == self.VALUE_UNINITIALIZED:
self._add_error(thread_status, self.MSG_ERROR, "Using variable '{:s}' at line {:d}, but it hasn't been initialized yet", dest_data["name"], statement.line)
elif dest_data["value"] == self.VALUE_FREED:
self._add_error(thread_status, self.MSG_ERROR, "Using variable '{:s}' at line {:d}, but it has been already freed", dest_data["name"], statement.line)
if (orig_type == self.TYPE_CRUST) and self._check_statement_is_crust(orig_var, orig_data):
# only check and modify if the origin variable IS really a crust one, and is being managed as a crust one
self._check_can_be_used(v["thread_status"], orig_var, statement.line)
......@@ -572,7 +585,9 @@ class crust(object):
function_status = function_data_base["value"]
has_ellipsis = function_data_base["ellipsis"]
if function_data[0]["crust"]:
if function_data is None:
retval_type = self.TYPE_NO_MATTER
elif function_data[0]["crust"]:
retval_type = self.TYPE_CRUST
retval_is_crust = True
else:
......@@ -582,16 +597,19 @@ class crust(object):
if function_status == self.VALUE_NULL:
self._add_error(thread_status, self.MSG_ERROR, "Using function pointer '{:s}' at line {:d} with NULL value", str(statement.name), statement.line)
elif function_status == self.VALUE_NOT_NULL_OR_NULL:
self._add_error(thread_status, self.MSG_WARNING, "Using function pointer '{:s}' at line {:d} with a possible NULL value", str(statement.name), statement.line)
if statement.right:
self._add_error(thread_status, self.MSG_WARNING, "Using variable '{:s}' at line {:d} with a possible NULL value", str(statement.name), statement.line)
else:
self._add_error(thread_status, self.MSG_WARNING, "Using function pointer '{:s}' at line {:d} with a possible NULL value", str(statement.name), statement.line)
elif function_status == self.VALUE_UNINITIALIZED:
self._add_error(thread_status, self.MSG_ERROR, "Using uninitialized function pointer '{:s}' at line {:d}", str(statement.name), statement.line)
if (((not has_ellipsis) and (len(function_data) - 1) != len(statement.function_params)) or
(has_ellipsis and (len(function_data) - 1) > len(statement.function_params))):
if ((function_data is not None) and (((not has_ellipsis) and (len(function_data) - 1) != len(statement.function_params)) or
(has_ellipsis and (len(function_data) - 1) > len(statement.function_params)))):
self._add_error(thread_status, self.MSG_CRITICAL, "Calling function '{:s}' at line {:d} with an incorrect number of parameters", statement.name, statement.line)
return [ {"thread_status":thread_status, "value":self.VALUE_NOT_NULL_OR_NULL, "type":retval_type, "condition":self.CONDITION_FALSE_TRUE, "node":statement} ]
if function_data[0]["crust"] and first:
if (retval_type == self.TYPE_CRUST) and first:
self._add_error(thread_status, self.MSG_ERROR, "Calling the function '{:s}' at line {:d}, but ignoring the crust-type return value", statement.name, statement.line)
# stores the execution branches and the return value for each one, in case there is a recycle parameter
......
......@@ -318,7 +318,7 @@ class Test(unittest.TestCase):
self._generic_test("unitest/test70.c", [ (crust.crust.MSG_ERROR, "Assigning a borrowed block into a local variable is not allowed (assigning '{:s}' at line {:d})", "param", 9) ])
def test071AssignmentToAndFromMemberOfBorrowBlock(self):
self._all_fine_test("unitest/test71.c")
self._generic_test("unitest/test71.c", [ (crust.crust.MSG_WARNING, "Using variable '{:s}' at line {:d} with a possible NULL value", "param", 10) ])
def test072AliasFreesBlock(self):
lib = self._all_fine_test("unitest/test72.c")
......@@ -596,9 +596,9 @@ class Test(unittest.TestCase):
self._check_is_alias(lib, "alias2", True, 3)
self._check_is_alias_of(lib, "alias2", "param", 3)
self._check_var_status(lib, "param", crust.crust.VALUE_NOT_NULL_OR_NULL, 4)
self._check_var_status(lib, "param", crust.crust.VALUE_NOT_NULL, 4)
self._check_var_status(lib, "alias1", crust.crust.VALUE_FREED, 4)
self._check_var_status(lib, "alias2", crust.crust.VALUE_NOT_NULL_OR_NULL, 4)
self._check_var_status(lib, "alias2", crust.crust.VALUE_NOT_NULL, 4)
self._check_is_alias(lib, "alias1", False, 4)
self._check_is_alias(lib, "alias2", True, 4)
self._check_is_alias_of(lib, "alias2", "param", 4)
......@@ -660,9 +660,9 @@ class Test(unittest.TestCase):
self._check_is_alias_of(lib, "alias2", "param2", 2)
self._check_var_status(lib, "param1", crust.crust.VALUE_FREED, 3)
self._check_var_status(lib, "param2", crust.crust.VALUE_NOT_NULL_OR_NULL, 3)
self._check_var_status(lib, "param2", crust.crust.VALUE_NOT_NULL, 3)
self._check_var_status(lib, "alias1", crust.crust.VALUE_FREED, 3)
self._check_var_status(lib, "alias2", crust.crust.VALUE_NOT_NULL_OR_NULL, 3)
self._check_var_status(lib, "alias2", crust.crust.VALUE_NOT_NULL, 3)
self._check_is_alias(lib, "alias1", True, 3)
self._check_is_alias(lib, "alias2", True, 3)
self._check_is_alias_of(lib, "alias1", "param1", 3)
......@@ -704,6 +704,14 @@ class Test(unittest.TestCase):
def test144CheckSignatures(self):
self._generic_test("unitest/test144.c", [ (crust.crust.MSG_CRITICAL, "Function definition for '{:s}' at line {:d}, file '{:s}' differs from definition at line {:d}, file '{:s}'", "main", 7, "unitest/test144.c", 5, "unitest/test144.c") ])
def test145CheckAssignAndCallPointerToPossibleNull(self):
self._generic_test("unitest/test145.c", [ (crust.crust.MSG_WARNING, "Using variable '{:s}' at line {:d} with a possible NULL value", "param1", 14), (crust.crust.MSG_WARNING, "Using variable '{:s}' at line {:d} with a possible NULL value", "param1", 15) ])
def test146CheckAssignToElementOfNullPointer(self):
self._generic_test("unitest/test146.c", [ (crust.crust.MSG_ERROR, "Using variable '{:s}' at line {:d}, but it has been already freed", "param1", 15) ])
def test147CheckAssignToElementOfUninitializedPointer(self):
self._generic_test("unitest/test147.c", [ (crust.crust.MSG_ERROR, "Using variable '{:s}' at line {:d}, but it hasn't been initialized yet", "param1", 15) ])
if __name__ == '__main__':
try:
......
......@@ -19,8 +19,10 @@ void main(crust_t param) {
__crust_debug__
alias1 = param->next;
__crust_debug__
alias2->next = alias1; // All this is legal
__crust_debug__
if (alias2 != NULL) {
alias2->next = alias1; // All this is legal
__crust_debug__
}
__crust_disable__
}
......@@ -17,8 +17,10 @@ void main(crust_t param) {
__crust_debug__
alias2 = alias1;
__crust_debug__
alias2->next = alias1; // All this is legal
__crust_debug__
if (alias2 != NULL) {
alias2->next = alias1; // All this is legal
__crust_debug__
}
__crust_disable__
}
......@@ -17,8 +17,10 @@ void main(crust_t param1, crust_t param2) {
__crust_debug__
alias2 = param2;
__crust_debug__
alias2->next = alias1; // All this is legal
__crust_debug__
if (alias2 != NULL) {
alias2->next = alias1; // All this is legal
__crust_debug__
}
__crust_disable__
}
typedef __crust_t__ unsigned char *crust_t;
typedef crust_t (*prueba)();
__crust_t__ struct tmp {
prueba function_p;
};
#define NULL ((void *)0)
crust_t function();
void main(struct tmp param1) {
param1->function_p = function;
param1->function_p();
__crust_disable__
}
typedef __crust_t__ unsigned char *crust_t;
typedef crust_t (*prueba)();
typedef __crust_t__ struct {
prueba function_p;
} *crust2_t;
#define NULL ((void *)0)
crust_t function();
void main(crust2_t param1) {
main(param1);
param1->function_p = function; // ERROR: param1 has been freed
__crust_disable__
}
typedef __crust_t__ unsigned char *crust_t;
typedef crust_t (*prueba)();
typedef __crust_t__ struct {
prueba function_p;
} *crust2_t;
#define NULL ((void *)0)
crust_t function();
void main() {
crust2_t param1;
param1->function_p = function; // ERROR: param1 has not been initialized
__crust_disable__
}
......@@ -7,5 +7,5 @@ typedef __crust_t__ struct {
void main(crust_t __crust_borrow__ param) {
int var2 = param->element;
param->element = var2; // All is legal
param->element = var2; // All is legal, except if we assume that 'param' can have a NULL value. That's why it returns a WARNING
}
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