Commit a98af1e3 authored by Sergio Costas's avatar Sergio Costas

Now ensures that, at the end of a function, there is at most one global...

Now ensures that, at the end of a function, there is at most one global function pointing to the same CRUST-type block
parent 759e3bd7
......@@ -14,7 +14,7 @@ The tags are automagically removed by the C Preprocessor, so
they are completely transparent to the compiler. That also
means that there are no fancy libraries, runtimes or expandable
macros: the source code is just standard, plain C. The tags just
serve to annotate specific information for the CRUST preprocessor,
allows to annotate specific information for the CRUST preprocessor,
but they aren't used during compilation.
It can be useful for projects where RUST is not feasible, like
......@@ -166,11 +166,12 @@ it must be stored in a CRUST *borrowed* variable.
Every time a CRUST variable is passed as an argument to a function, the
ownership is passed too, so, from that point, it will be in the FREED
state inside the calling function because it is assumed that the block
has been freed in the called function. There is an exception, and it is
when the argument in the called function is marked as *borrowed*. In that
case, the called function can't free the block, but can modify it, because
the ownership is retained in the caller function.
state inside the calling function until it is assigned a new block,
because it is assumed that the block has been freed in the called
function. There is an exception, and it is when the argument in the
called function is marked as *borrowed*. In that case, the called
function can't free the block, but can modify it, because the
ownership is retained in the caller function.
Trying to use a CRUST variable that is in UNINITIALIZED or FREED status is
an error, either using it as an argument when calling a function or accessing
......@@ -180,10 +181,22 @@ dangling pointer).
Global variables are an special case: since it is not possible to know
its state (because it can be changed outside the current function), they
are assumed to be in NOT_NULL_OR_NULL status when used as the origin, and
in UNINITIALIZED status when used as the destination. But it is important
to remember that assigning a CRUST variable to a global CRUST variable will
mark the former as FREED.
are assumed to be in NOT_NULL_OR_NULL status by default, and it is checked
at exit that they are in NOT_NULL, NULL or NOT_NULL_OR_NULL state (
never in FREED or UNINITIALIZED state). Assigning a CRUST variable to a global
variable is allowed, and the variable will not be marked as freed, but the
global variable will work like an alias variable (this is: freeing the
block pointed by a local variable copied in a global variable will result
in the global variable being also freed). It is possible to have several global
variables pointing to the same block during the life of the function.
When the execution reaches the end of the function all variables are checked.
It is an error to reach the end with CRUST variables in NOT_NULL or
NOT_NULL_OR_NULL state. There is an exception: when a local variable has been
copied to a global variable, it is not needed to free it. But at the end
of the execution, each block pointed by global variables must be pointed by
only one global variable (it is an error to reach the end of the function
and have two or more global variables pointing to the same block).
CRUST understand some comparisons, so this code:
......
......@@ -1340,15 +1340,31 @@ class crust(object):
def _check_global_vars(self, thread_status, line):
# check that there are no global vars with the same block,
# neither global vars in FREED state
copy1 = {}
copy2 = {}
for variable in thread_status["variables"][-1]:
data = thread_status["variables"][-1][variable]
if not data["crust"]:
continue
if not data["global"]:
continue
# we create two copies to be able to check if a block is pointed by more than one global variable
copy1[variable] = data.copy()
copy2[variable] = data.copy()
if data["value"] == self.VALUE_FREED:
self._add_error(thread_status, self.MSG_ERROR, "At exit point in line {:d}, global variable '{:s}' points to a block freed at line {:d}.", line, variable, data["init_line"])
checked = []
for var1 in copy1:
for var2 in copy2:
if 0 != checked.count(var2):
continue
if var1 == var2:
continue
if copy1[var1]["uid"] == copy2[var2]["uid"]:
self._add_error(thread_status, self.MSG_ERROR, "At exit point in line {:d}, global variable '{:s}' points to the same block than global variable {:s}.", line, var1, var2)
checked.append(var1)
def _check_blocks_in_use(self, thread_status, vars, line):
# check if there are memory blocks in use
......@@ -1410,9 +1426,11 @@ class crust(object):
if node.type == "END_BLOCK":
# check if there are blocks in use at the end of the block
self._check_blocks_in_use(thread_status, thread_status["variables"][0], node.line)
self._check_global_vars(thread_status, node.line)
# remove the last block of variables
thread_status["variables"] = thread_status["variables"][1:]
if (len(thread_status["variables"]) == 1):
# if we are at the end of the function, check the global variables
self._check_global_vars(thread_status, node.line)
return self._check_return_block(tree[1:], thread_status)
if node.type == "EMPTY_DECLARATOR":
......
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