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):
continue
if parameter.t_crust_recycle:
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:
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])):
......
......@@ -1010,7 +1010,7 @@ class Test(unittest.TestCase):
def test245AssignBorrowedToBorrowed(self):
self._all_fine_test("unitest/test245.c")
def test245ReturnBorrowedVariable(self):
def test246ReturnBorrowedVariable(self):
self._all_fine_test("unitest/test246.c")
def test247ReturnBorrowedParameter(self):
......@@ -1019,6 +1019,11 @@ class Test(unittest.TestCase):
def test248ReturnUninitializedBorrowedParameter(self):
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__':
try:
os.remove("error_list.txt")
......
......@@ -7,9 +7,9 @@ typedef __crust__ struct {
} *crust_t;
__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;
}
......@@ -23,7 +23,7 @@ void calling5(crust_t __crust_borrow__ param) {
void calling6(int v);
void main() {
void main(void) {
int a = 1 ? 3 : 0;
......
typedef __crust__ unsigned char *crust_t;
void function() {
void function(void) {
function3(3,5); // ERROR: function3 doesn't exist
}
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main(crust_t param1, crust_t param2) {
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main(crust_t param1, crust_t param2) {
......
......@@ -6,6 +6,6 @@ typedef int (*prueba)();
int function(int);
void main() {
void main(void) {
prueba test1 = function; // this is legal for CRUST because there are no crust-type parameters involved
}
......@@ -6,6 +6,6 @@ typedef crust_t (*prueba)();
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)
}
......@@ -6,6 +6,6 @@ typedef int (*prueba)(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)
}
......@@ -6,6 +6,6 @@ typedef int (*prueba)(unsigned char *, 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
}
......@@ -6,6 +6,6 @@ typedef int (*prueba)(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
}
......@@ -6,6 +6,6 @@ typedef int (*prueba)(crust_t, int);
int function(crust_t, int);
void main() {
void main(void) {
prueba test1 = function; // All fine, because both function signatures match
}
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main() {
void main(void) {
crust_t param;
int b;
......
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main() {
void main(void) {
crust_t param;
int b;
......
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main() {
void main(void) {
crust_t param;
int b;
......
void main() {
void main(void) {
int b = 1;
......
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
return 5;
......
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
return NULL;
......
......@@ -4,7 +4,7 @@ typedef char* (*prueba)(crust_t);
#define NULL ((void *)0)
prueba function();
prueba function(void);
void main(crust_t param1) {
prueba test1 = function();
......
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
}
......@@ -7,7 +7,7 @@ typedef struct t_crust_t *crust_t;
#define NULL ((void *)0)
void tmpfunc();
void tmpfunc(void);
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
return 0;
}
......@@ -8,7 +8,7 @@ typedef __crust__ struct {
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void function2(crust_t);
......
......@@ -8,7 +8,7 @@ typedef __crust__ struct {
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main(crust2_t param1) {
main(param1);
......
......@@ -8,9 +8,9 @@ typedef __crust__ struct {
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
void main() {
void main(void) {
crust2_t param1;
param1->function_p = function; // ERROR: param1 has not been initialized
}
......@@ -8,9 +8,9 @@ typedef struct {
#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
data1.function_p = function; // This is legal
}
__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
}
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t __crust_borrow__ function1();
crust_t __crust_borrow__ function1(void);
void main() {
void main(void) {
crust_t var1;
......
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function1();
crust_t function1(void);
void main() {
void main(void) {
crust_t var1;
......
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#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;
......
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function1();
crust_t function1(void);
void main() {
void main(void) {
__crust_borrow__ crust_t var1;
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t __crust_borrow__ function1();
crust_t __crust_borrow__ function1(void);
void main(__crust_borrow__ crust_t param1) {
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t main() {
crust_t main(void) {
int b;
b = 0;
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t main() {
crust_t main(void) {
int b = 5;
if (b == 7) {
......
typedef __crust__ unsigned char *crust_t;
crust_t function2() {
crust_t function2(void) {
crust_t param;
return param; // ERROR: returning an uninitialized variable
}
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#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
}
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function1();
crust_t function1(void);
void main() {
void main(void) {
char *var1;
......
......@@ -4,7 +4,7 @@ typedef __crust__ unsigned char *crust_t;
void function1(crust_t __crust_not_null__ param);
void main() {
void main(void) {
function1(NULL); // ERROR: the parameter must be not_null
}
......@@ -4,7 +4,7 @@ typedef __crust__ unsigned char *crust_t;
void function1(crust_t __crust_not_null__ param);
void main() {
void main(void) {
crust_t param = NULL;
function1(param); // ERROR: the parameter must be not_null
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t __crust_not_null__ function1();
crust_t __crust_not_null__ function1(void);
void function2(crust_t);
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#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
}
......@@ -2,9 +2,9 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t function();
crust_t function(void);
crust_t main() {
crust_t main(void) {
return function(); // this is fine.
}
typedef __crust__ unsigned char *crust_t;
void function() {
void function(void) {
crust_t param4 = NULL;
crust_t param1;
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
void function2(crust_t param);
void function() {
void function(void) {
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
......
......@@ -4,7 +4,7 @@ void function(void);
void function2(test);
void main() {
void main(void) {
function();
function2(NULL);
......
......@@ -8,9 +8,9 @@ struct crust_ts {
typedef __crust__ struct crust_ts* crust_t;
crust_t function2();
crust_t function2(void);
void function() {
void function(void) {
crust_t __crust_alias__ tmp1;
tmp1 = function2; // ERROR: can't assign a function pointer to an alias
......
#define NULL ((void *)0)
void main() {
void main(void) {
var = 5; // ERROR: this variable is unknown
}
typedef __crust__ unsigned char *crust_t;
void function() {
void function(void) {
crust_t param4;
int retval = (param4 == NULL) ? 1 : 0; // ERROR: conditional depends on an uninitialized variable
}
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
void main() {
void main(void) {
char str[5];
__crust_debug__
str[2] = 0; // This is fine
......
void main() {
void main(void) {
int v[7] = {0, 0, 0, 0, 0, 0, 0};
v[5] = 4;
......
void main() {
void main(void) {
int v[] = {0};
v[5] = 4; // all fine
......
void main() {
void main(void) {
struct test_t {
int v;
char b;
......
......@@ -10,7 +10,7 @@ struct crust_ts {
typedef __crust__ struct crust_ts* crust_t;
crust_t function() {
crust_t function(void) {
return (crust_t) malloc(800);
}
......@@ -10,7 +10,7 @@ struct crust_ts {
typedef __crust__ struct crust_ts* crust_t;
void function() {
void function(void) {
crust_t var = NULL;
......
......@@ -10,7 +10,7 @@ struct crust_ts {
typedef __crust__ struct crust_ts* crust_t;
crust_t function() {
crust_t function(void) {
return (crust_t) calloc(1, 800);
}
......@@ -10,7 +10,7 @@ struct crust_ts {
typedef __crust__ struct crust_ts* crust_t;
void function() {
void function(void) {
crust_t var = NULL;
......
typedef __crust__ int * crust_t;
void function() {
void function(void) {
crust_t param4;
crust_t param5 = param4; // ERROR: assigning an uninitialized variable
}
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
crust_t var1;
void main() {
void main(void) {
if (var1 == NULL) {
var1 = NULL; // just to access the variable
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
crust_t var1;
void main() {
void main(void) {
if (var1 == NULL) {
var1 = NULL; // just to access the variable
......
typedef __crust__ unsigned char *crust_t;
void main() {
void main(void) {
crust_t p;
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
void function(crust_t);
void main() {
void main(void) {
crust_t p = NULL;
// Here, p in in NULL state
......
typedef __crust__ int * crust_t;
void function() {
void function(void) {
int * param4 = NULL;
crust_t param5 = param4; // ERROR: assigning non-crust variable to crust variable
}
typedef __crust__ unsigned char *crust_t;
void main() {
void main(void) {
crust_t p;
......
void* function_name() {
void* function_name(void) {
return 0; // fine, it returns the equivalent to NULL
}
void* function_name() {
void* function_name(void) {
// ERROR; it must return something
}
......@@ -2,11 +2,11 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t __crust_borrow__ function1();
crust_t __crust_borrow__ function1(void);
void function2(crust_t __crust_borrow__);
void main() {
void main(void) {
__crust_borrow__ crust_t var1;
__crust_borrow__ crust_t var2;
......
......@@ -2,7 +2,7 @@ typedef __crust__ unsigned char *crust_t;
#define NULL ((void *)0)
crust_t __crust_borrow__ function2();
crust_t __crust_borrow__ function2(void);
crust_t __crust_borrow__ function1(crust_t __crust_borrow__ param1) {
crust_t __crust_borrow__ tmp;
......
// not allowed: C doesn't check that calls to functions without parameters honors the signature
// Thus, it is possible to call this function with several parameters, or assign it to a pointer
// to function with any type and number of parameters.
// To avoid this, it is a must to add "void" inside the parameter list;
// this is, the right definition is:
// int main(void) {
int main() {
return 0;
}
\ No newline at end of file
typedef __crust__ int * crust_t;
void function() {
void function(void) {
crust_t param4 = NULL;
int * param5 = param4; // ERROR: assigning crust variable to non-crust variable
}
// not allowed: C doesn't check that calls to functions without parameters honors the signature
// Thus, it is possible to call this function with several parameters, or assign it to a pointer
// to function with any type and number of parameters.
// To avoid this, it is a must to add "void" inside the parameter list;
// this is, the right definition is:
// int function(void);
int function();
\ No newline at end of file
typedef __crust__ unsigned char *crust_t;
void function() {
void function(void) {
int v = 5;
crust_t param = (crust_t) v; // This is legal
......
typedef __crust__ unsigned char *crust_t;
void function() {
void function(void) {
crust_t param = 5; // ERROR: assigning a constant (non-crust) to a crust variable
//ERROR: param is in use at the end of the function
......