Commit e2da88ed authored by Sergio Costas's avatar Sergio Costas

Don't allow to have functions with empty parameters

C doesn't check that calls to functions without parameters honors the
signature. Thus, it is possible to call a function defined as

void function() {...

with several parameters, or assign it to a pointer to function with any
type and number of parameters, and the compiler won't complain. To avoid
this, it is mandatory to put "void" inside the parameter list; so the
previous function must be written as:

void function(void) {...

This allows the compiler to detect illegal usages and assignments.
parent 68244136
...@@ -682,6 +682,8 @@ class crust(crust_helpers): ...@@ -682,6 +682,8 @@ class crust(crust_helpers):
continue continue
if parameter.t_crust_recycle: if parameter.t_crust_recycle:
counter += 1 counter += 1
if (node.function_params is None) or (len(node.function_params) == 0):
self._add_error({"debug_level": 0}, self.MSG_ERROR, "Function '{:s}' at line {:d} has no parameters (must have 'void' inside the parentheses)", node.name, node.line)
if counter > 1: if counter > 1:
self._add_error(thread_status, self.MSG_CRITICAL, "The function '{:s}', at line {:d}, has more than one RECYCLE argument", node.name, node.line) self._add_error(thread_status, self.MSG_CRITICAL, "The function '{:s}', at line {:d}, has more than one RECYCLE argument", node.name, node.line)
if (counter != 0) and (not self._check_statement_is_crust(node.return_value[0])): if (counter != 0) and (not self._check_statement_is_crust(node.return_value[0])):
......
...@@ -1010,7 +1010,7 @@ class Test(unittest.TestCase): ...@@ -1010,7 +1010,7 @@ class Test(unittest.TestCase):
def test245AssignBorrowedToBorrowed(self): def test245AssignBorrowedToBorrowed(self):
self._all_fine_test("unitest/test245.c") self._all_fine_test("unitest/test245.c")
def test245ReturnBorrowedVariable(self): def test246ReturnBorrowedVariable(self):
self._all_fine_test("unitest/test246.c") self._all_fine_test("unitest/test246.c")
def test247ReturnBorrowedParameter(self): def test247ReturnBorrowedParameter(self):
...@@ -1019,6 +1019,11 @@ class Test(unittest.TestCase): ...@@ -1019,6 +1019,11 @@ class Test(unittest.TestCase):
def test248ReturnUninitializedBorrowedParameter(self): def test248ReturnUninitializedBorrowedParameter(self):
self._generic_test("unitest/test248.c", [ (crust.crust.MSG_ERROR, "Returning variable '{:s}' at line {:d} is uninitialized", 'tmp', 8) ]) self._generic_test("unitest/test248.c", [ (crust.crust.MSG_ERROR, "Returning variable '{:s}' at line {:d} is uninitialized", 'tmp', 8) ])
def test249NoVoidOnEmptyParameterFunction(self):
self._generic_test("unitest/test249.c", [ (crust.crust.MSG_ERROR, "Function '{:s}' at line {:d} has no parameters (must have 'void' inside the parentheses)", 'main', 9) ])
def test250NoVoidOnEmptyParameterFunctionDefinition(self):
self._generic_test("unitest/test250.c", [ (crust.crust.MSG_ERROR, "Function '{:s}' at line {:d} has no parameters (must have 'void' inside the parentheses)", 'function', 9) ])
if __name__ == '__main__': if __name__ == '__main__':
try: try:
os.remove("error_list.txt") os.remove("error_list.txt")
......
...@@ -7,9 +7,9 @@ typedef __crust__ struct { ...@@ -7,9 +7,9 @@ typedef __crust__ struct {
} *crust_t; } *crust_t;
__crust__ unsigned char * calling(__crust__ unsigned char *param1, __crust_recycle__ unsigned char *param2, crust_t param3); __crust__ unsigned char * calling(__crust__ unsigned char *param1, __crust_recycle__ unsigned char *param2, crust_t param3);
__crust__ unsigned char * calling2(); __crust__ unsigned char * calling2(void);
__crust__ unsigned char * calling3() { __crust__ unsigned char * calling3(void) {
return NULL; return NULL;
} }
...@@ -23,7 +23,7 @@ void calling5(crust_t __crust_borrow__ param) { ...@@ -23,7 +23,7 @@ void calling5(crust_t __crust_borrow__ param) {
void calling6(int v); void calling6(int v);
void main() { void main(void) {
int a = 1 ? 3 : 0; int a = 1 ? 3 : 0;
......
typedef __crust__ unsigned char *crust_t; typedef __crust__ unsigned char *crust_t;
void function() { void function(void) {
function3(3,5); // ERROR: function3 doesn't exist function3(3,5); // ERROR: function3 doesn't exist
} }
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main(crust_t param1, crust_t param2) { void main(crust_t param1, crust_t param2) {
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main(crust_t param1, crust_t param2) { void main(crust_t param1, crust_t param2) {
......
...@@ -6,6 +6,6 @@ typedef int (*prueba)(); ...@@ -6,6 +6,6 @@ typedef int (*prueba)();
int function(int); int function(int);
void main() { void main(void) {
prueba test1 = function; // this is legal for CRUST because there are no crust-type parameters involved prueba test1 = function; // this is legal for CRUST because there are no crust-type parameters involved
} }
...@@ -6,6 +6,6 @@ typedef crust_t (*prueba)(); ...@@ -6,6 +6,6 @@ typedef crust_t (*prueba)();
crust_t function(int); crust_t function(int);
void main() { void main(void) {
prueba test1 = function; // ERROR: the number of parameters is different, and there are crust-type parameters involved (the return values) prueba test1 = function; // ERROR: the number of parameters is different, and there are crust-type parameters involved (the return values)
} }
...@@ -6,6 +6,6 @@ typedef int (*prueba)(int); ...@@ -6,6 +6,6 @@ typedef int (*prueba)(int);
int function(crust_t, int); int function(crust_t, int);
void main() { void main(void) {
prueba test1 = function; // ERROR: the number of parameters is different, and there are crust-type parameters involved (the first parameter) prueba test1 = function; // ERROR: the number of parameters is different, and there are crust-type parameters involved (the first parameter)
} }
...@@ -6,6 +6,6 @@ typedef int (*prueba)(unsigned char *, int); ...@@ -6,6 +6,6 @@ typedef int (*prueba)(unsigned char *, int);
int function(crust_t, int); int function(crust_t, int);
void main() { void main(void) {
prueba test1 = function; // ERROR: the first parameter doesn't match between both function definitions prueba test1 = function; // ERROR: the first parameter doesn't match between both function definitions
} }
...@@ -6,6 +6,6 @@ typedef int (*prueba)(crust_t, int); ...@@ -6,6 +6,6 @@ typedef int (*prueba)(crust_t, int);
crust_t function(crust_t, int); crust_t function(crust_t, int);
void main() { void main(void) {
prueba test1 = function; // ERROR: the first parameter doesn't match between both function definitions prueba test1 = function; // ERROR: the first parameter doesn't match between both function definitions
} }
...@@ -6,6 +6,6 @@ typedef int (*prueba)(crust_t, int); ...@@ -6,6 +6,6 @@ typedef int (*prueba)(crust_t, int);
int function(crust_t, int); int function(crust_t, int);
void main() { void main(void) {
prueba test1 = function; // All fine, because both function signatures match prueba test1 = function; // All fine, because both function signatures match
} }
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main() { void main(void) {
crust_t param; crust_t param;
int b; int b;
......
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main() { void main(void) {
crust_t param; crust_t param;
int b; int b;
......
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main() { void main(void) {
crust_t param; crust_t param;
int b; int b;
......
void main() { void main(void) {
int b = 1; int b = 1;
......
typedef __crust__ unsigned char *crust_t; typedef __crust__ unsigned char *crust_t;
int function() { int function(void) {
crust_t retval = function(); // Error: assigning non-crust return value to a crust variable crust_t retval = function(); // Error: assigning non-crust return value to a crust variable
return 5; return 5;
......
typedef __crust__ unsigned char *crust_t; typedef __crust__ unsigned char *crust_t;
crust_t function() { crust_t function(void) {
int retval = function(); // Error: assigning crust return value to a non-crust variable int retval = function(); // Error: assigning crust return value to a non-crust variable
return NULL; return NULL;
......
...@@ -4,7 +4,7 @@ typedef char* (*prueba)(crust_t); ...@@ -4,7 +4,7 @@ typedef char* (*prueba)(crust_t);
#define NULL ((void *)0) #define NULL ((void *)0)
prueba function(); prueba function(void);
void main(crust_t param1) { void main(crust_t param1) {
prueba test1 = function(); prueba test1 = function();
......
typedef __crust__ unsigned char crust_t; typedef __crust__ unsigned char crust_t;
void function() { void function(void) {
crust_t retval; // ERROR: the variable has crust type, but it is not a pointer crust_t retval; // ERROR: the variable has crust type, but it is not a pointer
} }
...@@ -7,7 +7,7 @@ typedef struct t_crust_t *crust_t; ...@@ -7,7 +7,7 @@ typedef struct t_crust_t *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
void tmpfunc(); void tmpfunc(void);
void main(crust_t param) { void main(crust_t param) {
......
__crust__ int function() { // ERROR: retval is crust, but it is not a pointer __crust__ int function(void) { // ERROR: retval is crust, but it is not a pointer
// empty function // empty function
return 0; return 0;
} }
...@@ -8,7 +8,7 @@ typedef __crust__ struct { ...@@ -8,7 +8,7 @@ typedef __crust__ struct {
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void function2(crust_t); void function2(crust_t);
......
...@@ -8,7 +8,7 @@ typedef __crust__ struct { ...@@ -8,7 +8,7 @@ typedef __crust__ struct {
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main(crust2_t param1) { void main(crust2_t param1) {
main(param1); main(param1);
......
...@@ -8,9 +8,9 @@ typedef __crust__ struct { ...@@ -8,9 +8,9 @@ typedef __crust__ struct {
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main() { void main(void) {
crust2_t param1; crust2_t param1;
param1->function_p = function; // ERROR: param1 has not been initialized param1->function_p = function; // ERROR: param1 has not been initialized
} }
...@@ -8,9 +8,9 @@ typedef struct { ...@@ -8,9 +8,9 @@ typedef struct {
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
void main() { void main(void) {
tmp_struct data1 = 1; // to ensure that it is not NULL tmp_struct data1 = 1; // to ensure that it is not NULL
data1.function_p = function; // This is legal data1.function_p = function; // This is legal
} }
__crust_borrow__ int *global_var; // ERROR: global variables can't be borrowed __crust_borrow__ int *global_var; // ERROR: global variables can't be borrowed
void main() { void main(void) {
__crust_borrow__ int *var; // It is valid to create local borrowed variables __crust_borrow__ int *var; // It is valid to create local borrowed variables
} }
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t __crust_borrow__ function1(); crust_t __crust_borrow__ function1(void);
void main() { void main(void) {
crust_t var1; crust_t var1;
......
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function1(); crust_t function1(void);
void main() { void main(void) {
crust_t var1; crust_t var1;
......
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t __crust_borrow__ function1(); crust_t __crust_borrow__ function1(void);
void main() { void main(void) {
__crust_borrow__ crust_t var1; __crust_borrow__ crust_t var1;
......
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function1(); crust_t function1(void);
void main() { void main(void) {
__crust_borrow__ crust_t var1; __crust_borrow__ crust_t var1;
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t __crust_borrow__ function1(); crust_t __crust_borrow__ function1(void);
void main(__crust_borrow__ crust_t param1) { void main(__crust_borrow__ crust_t param1) {
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t main() { crust_t main(void) {
int b; int b;
b = 0; b = 0;
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t main() { crust_t main(void) {
int b = 5; int b = 5;
if (b == 7) { if (b == 7) {
......
typedef __crust__ unsigned char *crust_t; typedef __crust__ unsigned char *crust_t;
crust_t function2() { crust_t function2(void) {
crust_t param; crust_t param;
return param; // ERROR: returning an uninitialized variable return param; // ERROR: returning an uninitialized variable
} }
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t __crust_borrow__ function1(); crust_t __crust_borrow__ function1(void);
void main() { void main(void) {
function1(); // It is legal to not use a returned crust value if it is borrowed function1(); // It is legal to not use a returned crust value if it is borrowed
} }
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function1(); crust_t function1(void);
void main() { void main(void) {
char *var1; char *var1;
......
...@@ -4,7 +4,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -4,7 +4,7 @@ typedef __crust__ unsigned char *crust_t;
void function1(crust_t __crust_not_null__ param); void function1(crust_t __crust_not_null__ param);
void main() { void main(void) {
function1(NULL); // ERROR: the parameter must be not_null function1(NULL); // ERROR: the parameter must be not_null
} }
...@@ -4,7 +4,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -4,7 +4,7 @@ typedef __crust__ unsigned char *crust_t;
void function1(crust_t __crust_not_null__ param); void function1(crust_t __crust_not_null__ param);
void main() { void main(void) {
crust_t param = NULL; crust_t param = NULL;
function1(param); // ERROR: the parameter must be not_null function1(param); // ERROR: the parameter must be not_null
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t __crust_not_null__ function1(); crust_t __crust_not_null__ function1(void);
void function2(crust_t); void function2(crust_t);
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t __crust_not_null__ main() { crust_t __crust_not_null__ main(void) {
return NULL; // ERROR: the return value can't be NULL return NULL; // ERROR: the return value can't be NULL
} }
...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0) #define NULL ((void *)0)
crust_t function(); crust_t function(void);
crust_t main() { crust_t main(void) {
return function(); // this is fine. return function(); // this is fine.
} }
typedef __crust__ unsigned char *crust_t; typedef __crust__ unsigned char *crust_t;
void function() { void function(void) {
crust_t param4 = NULL; crust_t param4 = NULL;
crust_t param1; crust_t param1;
......
...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t; ...@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
void function2(crust_t param); void function2(crust_t param);
void function() { void function(void) {
crust_t param4 = NULL; crust_t param4 = NULL;
int retval = (param4 == NULL) ? 1 : 0; // It is fine to just check if the variable is NULL or not NULL; if it is used after this, it will fail there int retval = (param4 == NULL) ? 1 : 0; // It is fine to just check if the variable is NULL or not NULL; if it is used after this, it will fail there
......
...@@ -4,7 +4,7 @@ void function(void); ...@@ -4,7 +4,7 @@ void function(void);
void function2(test); void function2(test);
void main() { void main(void) {
function(); function();
function2(NULL); function2(NULL);
......
...@@ -8,9 +8,9 @@ struct crust_ts { ...@@ -8,9 +8,9 @@ struct crust_ts {
typedef __crust__ struct crust_ts* crust_t; typedef __crust__ struct crust_ts* crust_t;
crust_t function2(); crust_t function2(void);
void function() { void function(void) {
crust_t __crust_alias__ tmp1; crust_t __crust_alias__ tmp1;
tmp1 = function2; // ERROR: can't assign a function pointer to an alias tmp1 = function2; // ERROR: can't assign a function pointer to an alias
......
#define NULL ((void *)0) #define NULL ((void *)0)
void main() { void main(void) {
var = 5; // ERROR: this variable is unknown var = 5; // ERROR: this variable is unknown
} }
typedef __crust__ unsigned char *crust_t; typedef __crust__ unsigned char *crust_t;
void function() { void function(void) {
crust_t param4;