diff --git a/regression/goto-analyzer/approx-array-variable-const-fp/main.c b/regression/goto-analyzer/approx-array-variable-const-fp/main.c new file mode 100644 index 00000000000..7896e3402c0 --- /dev/null +++ b/regression/goto-analyzer/approx-array-variable-const-fp/main.c @@ -0,0 +1,34 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + fp_tbl[i](); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/approx-array-variable-const-fp/test.desc b/regression/goto-analyzer/approx-array-variable-const-fp/test.desc new file mode 100644 index 00000000000..83a930d1c36 --- /dev/null +++ b/regression/goto-analyzer/approx-array-variable-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f2 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f3 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ +^warning: ignoring diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-cast-const-fp/main.c b/regression/goto-analyzer/approx-const-fp-array-variable-cast-const-fp/main.c new file mode 100644 index 00000000000..8fda2e71af4 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-cast-const-fp/main.c @@ -0,0 +1,41 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void(* const fp_tbl[3])(void) = +{ + (void(*)())f2, + (void(*)())f3, + (void(*)())f4, +}; + + +void func(int i) +{ + const void_fp fp = fp_tbl[i]; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-cast-const-fp/test.desc b/regression/goto-analyzer/approx-const-fp-array-variable-cast-const-fp/test.desc new file mode 100644 index 00000000000..a937e306d31 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-cast-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-fp-with-null/main.c b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp-with-null/main.c new file mode 100644 index 00000000000..72a600aa80c --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp-with-null/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4, 0}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + const void_fp fp = fp_tbl[i]; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-fp-with-null/test.desc b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp-with-null/test.desc new file mode 100644 index 00000000000..a937e306d31 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp-with-null/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-fp/main.c b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp/main.c new file mode 100644 index 00000000000..7eea22141bd --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + const void_fp fp = fp_tbl[i]; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-fp/test.desc b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp/test.desc new file mode 100644 index 00000000000..a937e306d31 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-pointer-const-struct-non-const-fp/main.c b/regression/goto-analyzer/approx-const-fp-array-variable-const-pointer-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..67d256f0c7b --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-pointer-const-struct-non-const-fp/main.c @@ -0,0 +1,50 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct action +{ + void_fp fun; +}; + +const struct action rec = { .fun = f2 }; +const struct action rec2 = { .fun = f3 }; +const struct action rec3 = { .fun = f4 }; + +const struct action * const action_list[4] = +{ + &rec, + &rec2, + &rec3, + &rec +}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + const void_fp fp = action_list[i]->fun; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-pointer-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/approx-const-fp-array-variable-const-pointer-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..a937e306d31 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-pointer-const-struct-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-struct-non-const-fp/main.c b/regression/goto-analyzer/approx-const-fp-array-variable-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..e058e5f3c4f --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-struct-non-const-fp/main.c @@ -0,0 +1,51 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +struct stable +{ + int x; + void (*fp)(void); +}; + +const struct stable stable_table [3] = +{ + { 1, f2 }, + { 2, f3 }, + { 3, f4 } +}; + +const struct stable another_table = { 4, f5 }; + + +void func(int i) +{ + const void_fp fp = stable_table[i].fp; + + // Illegal + // stable_table[1] = another_table; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + return 0; +} diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/approx-const-fp-array-variable-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..a937e306d31 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-const-struct-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-invalid-cast-const-fp/main.c b/regression/goto-analyzer/approx-const-fp-array-variable-invalid-cast-const-fp/main.c new file mode 100644 index 00000000000..ca882ffd6b3 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-invalid-cast-const-fp/main.c @@ -0,0 +1,77 @@ +#include + +int f1 (void) +{ + printf("%i\n", 1); + return 1; +} +int f2 (void) +{ + printf("%i\n", 2); + return 2; +} +int f3 (void) +{ + printf("%i\n", 3); + return 3; +} +int f4 (void) +{ + printf("%i\n", 4); + return 4; +} +int f5 (void) +{ + printf("%i\n", 5); + return 5; +} +int f6 (void) +{ + printf("%i\n", 6); + return 6; +} +int f7 (void) +{ + printf("%i\n", 7); + return 7; +} +int f8 (void) +{ + printf("%i\n", 8); + return 8; +} +int f9 (void) +{ + printf("%i\n", 9); + return 9; +} + +typedef void(*void_fp)(void); +typedef int(*int_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const int_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void(* const fp_tbl[3])(void) = +{ + (void(*)())f2, + (void(*)())f3, + (void(*)())f4, +}; + + +void func(int i) +{ + const void_fp fp = fp_tbl[i]; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + return 0; +} diff --git a/regression/goto-analyzer/approx-const-fp-array-variable-invalid-cast-const-fp/test.desc b/regression/goto-analyzer/approx-const-fp-array-variable-invalid-cast-const-fp/test.desc new file mode 100644 index 00000000000..b6e93d5b677 --- /dev/null +++ b/regression/goto-analyzer/approx-const-fp-array-variable-invalid-cast-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == \(void \(\*\)\(void\)\)f2 THEN GOTO [0-9]$ +^\s*IF fp == \(void \(\*\)\(void\)\)f3 THEN GOTO [0-9]$ +^\s*IF fp == \(void \(\*\)\(void\)\)f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ diff --git a/regression/goto-analyzer/no-match-array-literal-const-fp-null/main.c b/regression/goto-analyzer/no-match-array-literal-const-fp-null/main.c new file mode 100644 index 00000000000..93ed0af0d47 --- /dev/null +++ b/regression/goto-analyzer/no-match-array-literal-const-fp-null/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, NULL ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + fp_tbl[1](); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-array-literal-const-fp-null/test.desc b/regression/goto-analyzer/no-match-array-literal-const-fp-null/test.desc new file mode 100644 index 00000000000..4786993cade --- /dev/null +++ b/regression/goto-analyzer/no-match-array-literal-const-fp-null/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*ASSERT FALSE // invalid function pointer$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-array-const-pointer-const-fp-const-lost/main.c b/regression/goto-analyzer/no-match-const-array-const-pointer-const-fp-const-lost/main.c new file mode 100644 index 00000000000..a17acab6166 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-array-const-pointer-const-fp-const-lost/main.c @@ -0,0 +1,41 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp start_fp = f2; + const void_fp * const fp_tbl[] = { &start_fp, &start_fp, &start_fp }; + + // warning: loses const + void_fp * arr_ptr=fp_tbl[0]; + (*arr_ptr) = f5; + arr_ptr++; + (*arr_ptr) = f5; + + const void_fp * const fp = fp_tbl[1]; + + + (*fp)(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-array-const-pointer-const-fp-const-lost/test.desc b/regression/goto-analyzer/no-match-const-array-const-pointer-const-fp-const-lost/test.desc new file mode 100644 index 00000000000..9ac0520abde --- /dev/null +++ b/regression/goto-analyzer/no-match-const-array-const-pointer-const-fp-const-lost/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF \*fp == f1 THEN GOTO [0-9]$ +^\s*IF \*fp == f2 THEN GOTO [0-9]$ +^\s*IF \*fp == f3 THEN GOTO [0-9]$ +^\s*IF \*fp == f4 THEN GOTO [0-9]$ +^\s*IF \*fp == f5 THEN GOTO [0-9]$ +^\s*IF \*fp == f6 THEN GOTO [0-9]$ +^\s*IF \*fp == f7 THEN GOTO [0-9]$ +^\s*IF \*fp == f8 THEN GOTO [0-9]$ +^\s*IF \*fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-array-literal-const-fp-run-time/main.c b/regression/goto-analyzer/no-match-const-fp-array-literal-const-fp-run-time/main.c new file mode 100644 index 00000000000..ee9ba95cb57 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-literal-const-fp-run-time/main.c @@ -0,0 +1,36 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i, int j) +{ + const void_fp fp_tbl[] = {fp_all[i*2], fp_all[j+1]}; + // Illegal: + //fp_tbl[1] = f4; + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i,0); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-array-literal-const-fp-run-time/test.desc b/regression/goto-analyzer/no-match-const-fp-array-literal-const-fp-run-time/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-literal-const-fp-run-time/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp-run-time/main.c b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp-run-time/main.c new file mode 100644 index 00000000000..fa1cf231a50 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp-run-time/main.c @@ -0,0 +1,34 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i, int j) +{ + void_fp fp_tbl[] = {fp_all[i*2], fp_all[j+1]}; + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i,0); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp-run-time/test.desc b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp-run-time/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp-run-time/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp/main.c new file mode 100644 index 00000000000..88b4edcf448 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp/main.c @@ -0,0 +1,38 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +void_fp fp_tbl[] = {f2, f3, f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(void_fp fp, int i) +{ + // It is concievable this could be checked and seen the first value + // of the array is unchanged but is kind of a weird edge case. + fp_tbl[2] = fp; + const void_fp fp2 = fp_tbl[1]; + fp2(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(fp_all[i+3], i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp/test.desc new file mode 100644 index 00000000000..9c0926c2e7a --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-literal-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp2 == f1 THEN GOTO [0-9]$ +^\s*IF fp2 == f2 THEN GOTO [0-9]$ +^\s*IF fp2 == f3 THEN GOTO [0-9]$ +^\s*IF fp2 == f4 THEN GOTO [0-9]$ +^\s*IF fp2 == f5 THEN GOTO [0-9]$ +^\s*IF fp2 == f6 THEN GOTO [0-9]$ +^\s*IF fp2 == f7 THEN GOTO [0-9]$ +^\s*IF fp2 == f8 THEN GOTO [0-9]$ +^\s*IF fp2 == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-array-non-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-array-non-const-fp/main.c new file mode 100644 index 00000000000..38d09cfb14e --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-non-const-fp/main.c @@ -0,0 +1,36 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +void_fp fp_tbl[] = {f2, f3, f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(void_fp fp, int i) +{ + fp_tbl[2] = fp; + const void_fp fp2 = fp_tbl[2]; + fp2(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(fp_all[i+3], i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-array-non-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-array-non-const-fp/test.desc new file mode 100644 index 00000000000..9c0926c2e7a --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-array-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp2 == f1 THEN GOTO [0-9]$ +^\s*IF fp2 == f2 THEN GOTO [0-9]$ +^\s*IF fp2 == f3 THEN GOTO [0-9]$ +^\s*IF fp2 == f4 THEN GOTO [0-9]$ +^\s*IF fp2 == f5 THEN GOTO [0-9]$ +^\s*IF fp2 == f6 THEN GOTO [0-9]$ +^\s*IF fp2 == f7 THEN GOTO [0-9]$ +^\s*IF fp2 == f8 THEN GOTO [0-9]$ +^\s*IF fp2 == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-binary-op-const-lost/main.c b/regression/goto-analyzer/no-match-const-fp-binary-op-const-lost/main.c new file mode 100644 index 00000000000..7f5c0ea3755 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-binary-op-const-lost/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + + // Warning: this loses const-ness of f2 + void_fp * p2fp = 0 + ((void_fp*)&fp); + *p2fp = &f4; + + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-binary-op-const-lost/test.desc b/regression/goto-analyzer/no-match-const-fp-binary-op-const-lost/test.desc new file mode 100644 index 00000000000..e8357d911c6 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-binary-op-const-lost/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-array-index-lost/main.c b/regression/goto-analyzer/no-match-const-fp-const-array-index-lost/main.c new file mode 100644 index 00000000000..b3dafeff777 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-array-index-lost/main.c @@ -0,0 +1,40 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp_tbl[] = {f2, f3 ,f4}; + + // warning: loses const + void_fp * arr_ptr=&fp_tbl[0]; + (*arr_ptr) = f5; + arr_ptr++; + (*arr_ptr) = f5; + + const void_fp * const fp = &fp_tbl[1]; + + + (*fp)(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-array-index-lost/test.desc b/regression/goto-analyzer/no-match-const-fp-const-array-index-lost/test.desc new file mode 100644 index 00000000000..9ac0520abde --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-array-index-lost/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF \*fp == f1 THEN GOTO [0-9]$ +^\s*IF \*fp == f2 THEN GOTO [0-9]$ +^\s*IF \*fp == f3 THEN GOTO [0-9]$ +^\s*IF \*fp == f4 THEN GOTO [0-9]$ +^\s*IF \*fp == f5 THEN GOTO [0-9]$ +^\s*IF \*fp == f6 THEN GOTO [0-9]$ +^\s*IF \*fp == f7 THEN GOTO [0-9]$ +^\s*IF \*fp == f8 THEN GOTO [0-9]$ +^\s*IF \*fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-array-lost/main.c b/regression/goto-analyzer/no-match-const-fp-const-array-lost/main.c new file mode 100644 index 00000000000..d27da78d0b7 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-array-lost/main.c @@ -0,0 +1,40 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp_tbl[] = {f2, f3 ,f4}; + + // warning: loses const + void_fp * arr_ptr=fp_tbl; + (*arr_ptr) = f5; + arr_ptr++; + (*arr_ptr) = f5; + + const void_fp * const fp = &fp_tbl[1]; + + + (*fp)(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-array-lost/test.desc b/regression/goto-analyzer/no-match-const-fp-const-array-lost/test.desc new file mode 100644 index 00000000000..9ac0520abde --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-array-lost/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF \*fp == f1 THEN GOTO [0-9]$ +^\s*IF \*fp == f2 THEN GOTO [0-9]$ +^\s*IF \*fp == f3 THEN GOTO [0-9]$ +^\s*IF \*fp == f4 THEN GOTO [0-9]$ +^\s*IF \*fp == f5 THEN GOTO [0-9]$ +^\s*IF \*fp == f6 THEN GOTO [0-9]$ +^\s*IF \*fp == f7 THEN GOTO [0-9]$ +^\s*IF \*fp == f8 THEN GOTO [0-9]$ +^\s*IF \*fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-cast/main.c b/regression/goto-analyzer/no-match-const-fp-const-cast/main.c new file mode 100644 index 00000000000..b9bd141e6f0 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-cast/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + + // Warning: this loses const-ness of f2 + void_fp * p2fp = (void_fp*)&fp; + *p2fp = &f4; + + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-cast/test.desc b/regression/goto-analyzer/no-match-const-fp-const-cast/test.desc new file mode 100644 index 00000000000..e8357d911c6 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-cast/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-fp-null/main.c b/regression/goto-analyzer/no-match-const-fp-const-fp-null/main.c new file mode 100644 index 00000000000..67c501302a6 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-fp-null/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = NULL; + const void_fp fp2 = fp; + fp2(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-fp-null/test.desc b/regression/goto-analyzer/no-match-const-fp-const-fp-null/test.desc new file mode 100644 index 00000000000..4786993cade --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-fp-null/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*ASSERT FALSE // invalid function pointer$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-lost/main.c b/regression/goto-analyzer/no-match-const-fp-const-lost/main.c new file mode 100644 index 00000000000..d2724684066 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-lost/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + + // Warning: this loses const-ness of f2 + void_fp * p2fp = &fp; + *p2fp = &f4; + + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-lost/test.desc b/regression/goto-analyzer/no-match-const-fp-const-lost/test.desc new file mode 100644 index 00000000000..e8357d911c6 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-lost/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-pointer-const-struct-const-fp-null/main.c b/regression/goto-analyzer/no-match-const-fp-const-pointer-const-struct-const-fp-null/main.c new file mode 100644 index 00000000000..76671ef3829 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-pointer-const-struct-const-fp-null/main.c @@ -0,0 +1,44 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + + +typedef struct fp_container +{ + int x; + const void_fp pointer; +} fp_container; + + + +void func() +{ + const fp_container container = {.x = 10, .pointer = f3}; + const fp_container container2 = {.x = 10, .pointer = f4}; + const fp_container * const container_ptr = NULL; + + // Illegal: + //container_ptr = &container2; + //container_ptr->pointer = f4; + + container_ptr->pointer(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-pointer-const-struct-const-fp-null/test.desc b/regression/goto-analyzer/no-match-const-fp-const-pointer-const-struct-const-fp-null/test.desc new file mode 100644 index 00000000000..25b505c0a0f --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-pointer-const-struct-const-fp-null/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*ASSERT FALSE // invalid function pointer$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-const-pointer-non-const-struct-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-const-pointer-non-const-struct-const-fp/main.c new file mode 100644 index 00000000000..3f55ff255dd --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-pointer-non-const-struct-const-fp/main.c @@ -0,0 +1,47 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct state +{ + int x; // Mutable! + const void_fp go; +}; +struct state thing = {0, &f2}; +struct state other_thing = {0, &f4}; +struct state * const pts = &thing; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + // Illegal + //pts=&other_thing; + // thing.go=&f6; + thing = other_thing; + const void_fp fp = pts->go; + + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-const-pointer-non-const-struct-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-const-pointer-non-const-struct-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-const-pointer-non-const-struct-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-dereference-const-pointer-null/main.c b/regression/goto-analyzer/no-match-const-fp-dereference-const-pointer-null/main.c new file mode 100644 index 00000000000..e4048adb8cb --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-dereference-const-pointer-null/main.c @@ -0,0 +1,36 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f3; + const void_fp fp2 = f4; + const void_fp* const p2fp = NULL; + // Illegal: + //p2fp = &fp2; + //fp = f5; + const void_fp final_fp=*p2fp; + final_fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-dereference-const-pointer-null/test.desc b/regression/goto-analyzer/no-match-const-fp-dereference-const-pointer-null/test.desc new file mode 100644 index 00000000000..25b505c0a0f --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-dereference-const-pointer-null/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*ASSERT FALSE // invalid function pointer$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-dereference-non-const-pointer-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-dereference-non-const-pointer-const-fp/main.c new file mode 100644 index 00000000000..30e4947c2d7 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-dereference-non-const-pointer-const-fp/main.c @@ -0,0 +1,40 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f3; + const void_fp fp2 = f4; + const void_fp* p2fp = &fp; + + + // Illegal: + //fp = f5; + + // legal: + p2fp = &fp2; + const void_fp final_fp=*p2fp; + final_fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-dereference-non-const-pointer-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-dereference-non-const-pointer-const-fp/test.desc new file mode 100644 index 00000000000..61a7ec29e6b --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-dereference-non-const-pointer-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF final_fp == f1 THEN GOTO [0-9]$ +^\s*IF final_fp == f2 THEN GOTO [0-9]$ +^\s*IF final_fp == f3 THEN GOTO [0-9]$ +^\s*IF final_fp == f4 THEN GOTO [0-9]$ +^\s*IF final_fp == f5 THEN GOTO [0-9]$ +^\s*IF final_fp == f6 THEN GOTO [0-9]$ +^\s*IF final_fp == f7 THEN GOTO [0-9]$ +^\s*IF final_fp == f8 THEN GOTO [0-9]$ +^\s*IF final_fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-dynamic-array-non-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-dynamic-array-non-const-fp/main.c new file mode 100644 index 00000000000..d7d4820d29c --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-dynamic-array-non-const-fp/main.c @@ -0,0 +1,39 @@ +#include +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp * const fp_tbl= malloc(sizeof(void_fp) * 3); + fp_tbl[0]=f2; + fp_tbl[1]=f3; + fp_tbl[2]=f4; + + // Illegal + //fp_tbl = malloc(sizeof(void_fp) * 10); + + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-dynamic-array-non-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-dynamic-array-non-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-dynamic-array-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-fp-direct-assignment/main.c b/regression/goto-analyzer/no-match-const-fp-non-const-fp-direct-assignment/main.c new file mode 100644 index 00000000000..6c9ba5514e7 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-fp-direct-assignment/main.c @@ -0,0 +1,32 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp fp = f2; + fp = f3; + const void_fp fp2 = fp; + fp2(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-fp-direct-assignment/test.desc b/regression/goto-analyzer/no-match-const-fp-non-const-fp-direct-assignment/test.desc new file mode 100644 index 00000000000..13d0c5353ce --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-fp-direct-assignment/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*IF fp2 == f1 THEN GOTO [0-9]$ +^\s*IF fp2 == f2 THEN GOTO [0-9]$ +^\s*IF fp2 == f3 THEN GOTO [0-9]$ +^\s*IF fp2 == f4 THEN GOTO [0-9]$ +^\s*IF fp2 == f5 THEN GOTO [0-9]$ +^\s*IF fp2 == f6 THEN GOTO [0-9]$ +^\s*IF fp2 == f7 THEN GOTO [0-9]$ +^\s*IF fp2 == f8 THEN GOTO [0-9]$ +^\s*IF fp2 == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-pointer-non-const-struct-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-non-const-pointer-non-const-struct-const-fp/main.c new file mode 100644 index 00000000000..bb40b1a53c1 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-pointer-non-const-struct-const-fp/main.c @@ -0,0 +1,47 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct state +{ + int x; // Mutable! + const void_fp go; +}; +struct state thing = {0, &f2}; +struct state other_thing = {0, &f4}; + +// This shouldn't work +struct state * pts = &thing; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + // This shouldn't work since + pts = &other_thing; + const void_fp fp = pts->go; + fp(); +} + + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-pointer-non-const-struct-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-non-const-pointer-non-const-struct-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-pointer-non-const-struct-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-struct-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-non-const-struct-const-fp/main.c new file mode 100644 index 00000000000..ed86d4c39c6 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-struct-const-fp/main.c @@ -0,0 +1,43 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct state +{ + int x; // Mutable! + const void_fp go; +}; +struct state thing = {0, &f2}; + +struct state other_thing = {0, &f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + thing = other_thing; + const void_fp fp = thing.go; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-struct-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-non-const-struct-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-struct-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-struct-non-const-fp/main.c b/regression/goto-analyzer/no-match-const-fp-non-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..7d8b2584388 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-struct-non-const-fp/main.c @@ -0,0 +1,43 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct action +{ + int x; + void_fp fun; +}; + +struct action rec = { .x = 4, .fun = f2 }; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + // Can mutate + rec.fun=f4; + const void_fp fp = rec.fun; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-non-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/no-match-const-fp-non-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-non-const-struct-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-null/main.c b/regression/goto-analyzer/no-match-const-fp-null/main.c new file mode 100644 index 00000000000..16c65f9f845 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-null/main.c @@ -0,0 +1,30 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = NULL; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-null/test.desc b/regression/goto-analyzer/no-match-const-fp-null/test.desc new file mode 100644 index 00000000000..267ec2284f7 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-null/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*ASSERT FALSE // invalid function pointer$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-fp-ternerary-op-const-lost/main.c b/regression/goto-analyzer/no-match-const-fp-ternerary-op-const-lost/main.c new file mode 100644 index 00000000000..ba5bcad694a --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-ternerary-op-const-lost/main.c @@ -0,0 +1,36 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int x) +{ + const void_fp fp = f2; + void_fp non_const_fp = f7; + + // Warning: this loses const-ness of f2 + void_fp * p2fp = x > 0 ? ((void_fp*)&fp) : &non_const_fp; + *p2fp = &f4; + + fp(); +} + +int main() +{ + func(1); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-fp-ternerary-op-const-lost/test.desc b/regression/goto-analyzer/no-match-const-fp-ternerary-op-const-lost/test.desc new file mode 100644 index 00000000000..e8357d911c6 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-fp-ternerary-op-const-lost/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-pointer-const-struct-const-fp-const-cast/main.c b/regression/goto-analyzer/no-match-const-pointer-const-struct-const-fp-const-cast/main.c new file mode 100644 index 00000000000..b7b9e4d2b30 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-pointer-const-struct-const-fp-const-cast/main.c @@ -0,0 +1,45 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_cc +{ + int x; + void_fp fp; +} fp_cc; + + + +void func() +{ + const fp_cc container_container = { .fp = f2, .x = 4 }; + + const fp_cc * const container_pointer = &container_container; + + fp_cc* container_pointer_modifier = (fp_cc*) container_pointer; + container_pointer_modifier->fp = f4; + + // Illegal: + // container_container.container = &f4; + + container_pointer->fp(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/no-match-const-pointer-const-struct-const-fp-const-cast/test.desc b/regression/goto-analyzer/no-match-const-pointer-const-struct-const-fp-const-cast/test.desc new file mode 100644 index 00000000000..2f4b2832b4d --- /dev/null +++ b/regression/goto-analyzer/no-match-const-pointer-const-struct-const-fp-const-cast/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF container_pointer->fp == f1 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f2 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f3 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f4 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f5 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f6 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f7 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f8 THEN GOTO [0-9]$ +^\s*IF container_pointer->fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-pointer-non-const-struct-const-fp/main.c b/regression/goto-analyzer/no-match-const-pointer-non-const-struct-const-fp/main.c new file mode 100644 index 00000000000..bf4bb45d094 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-pointer-non-const-struct-const-fp/main.c @@ -0,0 +1,43 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct state +{ + int x; // Mutable! + const void_fp go; +}; +struct state thing = {0, &f2}; +struct state other_thing = {0, &f4}; +struct state const * const pts = &thing; + + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + thing = other_thing; + pts->go(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-pointer-non-const-struct-const-fp/test.desc b/regression/goto-analyzer/no-match-const-pointer-non-const-struct-const-fp/test.desc new file mode 100644 index 00000000000..2760fadd576 --- /dev/null +++ b/regression/goto-analyzer/no-match-const-pointer-non-const-struct-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF pts->go == f1 THEN GOTO [0-9]$ +^\s*IF pts->go == f2 THEN GOTO [0-9]$ +^\s*IF pts->go == f3 THEN GOTO [0-9]$ +^\s*IF pts->go == f4 THEN GOTO [0-9]$ +^\s*IF pts->go == f5 THEN GOTO [0-9]$ +^\s*IF pts->go == f6 THEN GOTO [0-9]$ +^\s*IF pts->go == f7 THEN GOTO [0-9]$ +^\s*IF pts->go == f8 THEN GOTO [0-9]$ +^\s*IF pts->go == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-const-struct-non-const-fp-null/main.c b/regression/goto-analyzer/no-match-const-struct-non-const-fp-null/main.c new file mode 100644 index 00000000000..6e24a0d8d4c --- /dev/null +++ b/regression/goto-analyzer/no-match-const-struct-non-const-fp-null/main.c @@ -0,0 +1,40 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct action +{ + int x; + const void_fp fun; +}; + +const struct action rec = { .x = 4, .fun = NULL }; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + rec.fun(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-const-struct-non-const-fp-null/test.desc b/regression/goto-analyzer/no-match-const-struct-non-const-fp-null/test.desc new file mode 100644 index 00000000000..25b505c0a0f --- /dev/null +++ b/regression/goto-analyzer/no-match-const-struct-non-const-fp-null/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*ASSERT FALSE // invalid function pointer$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-dereference-const-pointer-const-array-literal-pointer-const-fp/main.c b/regression/goto-analyzer/no-match-dereference-const-pointer-const-array-literal-pointer-const-fp/main.c new file mode 100644 index 00000000000..5d857ffcfe7 --- /dev/null +++ b/regression/goto-analyzer/no-match-dereference-const-pointer-const-array-literal-pointer-const-fp/main.c @@ -0,0 +1,52 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_container +{ + int x; + const void_fp* const fp_tbl[3]; +} fp_container; + + + +void func() +{ + void_fp f2meta = &f2; + void_fp f3meta = &f3; + void_fp f4meta = &f4; + + void_fp f5meta = &f5; + void_fp f6meta = &f6; + void_fp f7meta = &f7; + + const fp_container container = { .x = 4, .fp_tbl = {&f2meta ,&f3meta, &f4meta} }; + const fp_container container2 = { .x = 5, .fp_tbl = {&f5meta ,&f6meta, &f7meta} }; + + f3meta = &f5; + // Illegal: + // container.fp_tbl = alternatate_fp_tbl; + // container.fp_tbl[1] = f4; + const fp_container * const container_ptr=&container; + //container_ptr=&container2; + (*container_ptr->fp_tbl[1])(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/no-match-dereference-const-pointer-const-array-literal-pointer-const-fp/test.desc b/regression/goto-analyzer/no-match-dereference-const-pointer-const-array-literal-pointer-const-fp/test.desc new file mode 100644 index 00000000000..7e0aca75523 --- /dev/null +++ b/regression/goto-analyzer/no-match-dereference-const-pointer-const-array-literal-pointer-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f1 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f2 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f3 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f4 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f5 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f6 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f7 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f8 THEN GOTO [0-9]$ +^\s*IF \*container_ptr->fp_tbl\[\(signed long int\)1\] == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-dereference-non-const-struct-const-pointer-const-fp/main.c b/regression/goto-analyzer/no-match-dereference-non-const-struct-const-pointer-const-fp/main.c new file mode 100644 index 00000000000..b0be4e4837c --- /dev/null +++ b/regression/goto-analyzer/no-match-dereference-non-const-struct-const-pointer-const-fp/main.c @@ -0,0 +1,46 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_cc +{ + int x; + const void_fp * const container; +} fp_cc; + + + +void func() +{ + const void_fp meta_fp = &f3; + const void_fp meta_fp2 = &f4; + + fp_cc container_container2 = { .container = &meta_fp2, .x = 4 }; + fp_cc container_container = { .container = &meta_fp, .x = 4 }; + container_container = container_container2; + + // Illegal: + //meta_fp = &f4; + //container_container.container = &f4; + + (*container_container.container)(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/no-match-dereference-non-const-struct-const-pointer-const-fp/test.desc b/regression/goto-analyzer/no-match-dereference-non-const-struct-const-pointer-const-fp/test.desc new file mode 100644 index 00000000000..f55defde97b --- /dev/null +++ b/regression/goto-analyzer/no-match-dereference-non-const-struct-const-pointer-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF \*container_container\.container == f1 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f2 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f3 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f4 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f5 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f6 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f7 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f8 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-dereference-non-const-struct-non-const-pointer-const-fp/main.c b/regression/goto-analyzer/no-match-dereference-non-const-struct-non-const-pointer-const-fp/main.c new file mode 100644 index 00000000000..28110c56d01 --- /dev/null +++ b/regression/goto-analyzer/no-match-dereference-non-const-struct-non-const-pointer-const-fp/main.c @@ -0,0 +1,43 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_cc +{ + int x; + const void_fp * container; +} fp_cc; + + + +void func() +{ + const void_fp meta_fp = &f3; + const void_fp meta_fp2 = &f4; + fp_cc container_container = { .container = &meta_fp, .x = 4 }; + + // Illegal: + //meta_fp = &f4; + container_container.container = &meta_fp2; + + (*container_container.container)(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/no-match-dereference-non-const-struct-non-const-pointer-const-fp/test.desc b/regression/goto-analyzer/no-match-dereference-non-const-struct-non-const-pointer-const-fp/test.desc new file mode 100644 index 00000000000..f55defde97b --- /dev/null +++ b/regression/goto-analyzer/no-match-dereference-non-const-struct-non-const-pointer-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF \*container_container\.container == f1 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f2 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f3 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f4 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f5 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f6 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f7 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f8 THEN GOTO [0-9]$ +^\s*IF \*container_container\.container == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-non-const-fp-const-fp-direct-assignment/main.c b/regression/goto-analyzer/no-match-non-const-fp-const-fp-direct-assignment/main.c new file mode 100644 index 00000000000..4487db8b047 --- /dev/null +++ b/regression/goto-analyzer/no-match-non-const-fp-const-fp-direct-assignment/main.c @@ -0,0 +1,33 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + const void_fp fp3 = f4; + void_fp fp2 = fp; + fp2 = fp3; + fp2(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-non-const-fp-const-fp-direct-assignment/test.desc b/regression/goto-analyzer/no-match-non-const-fp-const-fp-direct-assignment/test.desc new file mode 100644 index 00000000000..13d0c5353ce --- /dev/null +++ b/regression/goto-analyzer/no-match-non-const-fp-const-fp-direct-assignment/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*IF fp2 == f1 THEN GOTO [0-9]$ +^\s*IF fp2 == f2 THEN GOTO [0-9]$ +^\s*IF fp2 == f3 THEN GOTO [0-9]$ +^\s*IF fp2 == f4 THEN GOTO [0-9]$ +^\s*IF fp2 == f5 THEN GOTO [0-9]$ +^\s*IF fp2 == f6 THEN GOTO [0-9]$ +^\s*IF fp2 == f7 THEN GOTO [0-9]$ +^\s*IF fp2 == f8 THEN GOTO [0-9]$ +^\s*IF fp2 == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-non-const-fp/main.c b/regression/goto-analyzer/no-match-non-const-fp/main.c new file mode 100644 index 00000000000..80c8c863ff5 --- /dev/null +++ b/regression/goto-analyzer/no-match-non-const-fp/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp fp = f2; + fp = f3; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/no-match-non-const-fp/test.desc b/regression/goto-analyzer/no-match-non-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-parameter-const-fp/main.c b/regression/goto-analyzer/no-match-parameter-const-fp/main.c new file mode 100644 index 00000000000..23e73aabdc0 --- /dev/null +++ b/regression/goto-analyzer/no-match-parameter-const-fp/main.c @@ -0,0 +1,32 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(const void_fp fp) +{ + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(fp_all[i]); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-parameter-const-fp/test.desc b/regression/goto-analyzer/no-match-parameter-const-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-parameter-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-parameter-fp/main.c b/regression/goto-analyzer/no-match-parameter-fp/main.c new file mode 100644 index 00000000000..332df257368 --- /dev/null +++ b/regression/goto-analyzer/no-match-parameter-fp/main.c @@ -0,0 +1,32 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(void_fp fp) +{ + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(fp_all[i]); + } + + return 0; +} diff --git a/regression/goto-analyzer/no-match-parameter-fp/test.desc b/regression/goto-analyzer/no-match-parameter-fp/test.desc new file mode 100644 index 00000000000..997ec886207 --- /dev/null +++ b/regression/goto-analyzer/no-match-parameter-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/no-match-pointer-const-struct-array-literal-non-const-fp/main.c b/regression/goto-analyzer/no-match-pointer-const-struct-array-literal-non-const-fp/main.c new file mode 100644 index 00000000000..c9d632f43b9 --- /dev/null +++ b/regression/goto-analyzer/no-match-pointer-const-struct-array-literal-non-const-fp/main.c @@ -0,0 +1,42 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_container +{ + void_fp fp_tbl[3]; +} fp_container; + + + +void func() +{ + const fp_container container = { .fp_tbl = {f2 ,f3, f4} }; + const void_fp alternatate_fp_tbl[] = {f5 ,f6, f7}; + const fp_container container2 = { .fp_tbl = {f5 ,f6, f7} }; + // Illegal: + // container.fp_tbl = alternatate_fp_tbl; + // container.fp_tbl[1] = f4; + const fp_container *container_ptr=&container; + container_ptr=&container2; + container_ptr->fp_tbl[1](); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/no-match-pointer-const-struct-array-literal-non-const-fp/test.desc b/regression/goto-analyzer/no-match-pointer-const-struct-array-literal-non-const-fp/test.desc new file mode 100644 index 00000000000..83a4d98d9f4 --- /dev/null +++ b/regression/goto-analyzer/no-match-pointer-const-struct-array-literal-non-const-fp/test.desc @@ -0,0 +1,17 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f1 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f2 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f3 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f4 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f5 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f6 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f7 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f8 THEN GOTO [0-9]$ +^\s*IF container_ptr->fp_tbl\[\(signed long int\)1\] == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-array-calculation-const-fp/main.c b/regression/goto-analyzer/precise-array-calculation-const-fp/main.c new file mode 100644 index 00000000000..a61d95186aa --- /dev/null +++ b/regression/goto-analyzer/precise-array-calculation-const-fp/main.c @@ -0,0 +1,32 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const short short_const_variable=1; + fp_tbl[(signed long int)((signed int)short_const_variable & 0x1)](); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-array-calculation-const-fp/test.desc b/regression/goto-analyzer/precise-array-calculation-const-fp/test.desc new file mode 100644 index 00000000000..fad0e6c7a1d --- /dev/null +++ b/regression/goto-analyzer/precise-array-calculation-const-fp/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-array-literal-const-fp/main.c b/regression/goto-analyzer/precise-array-literal-const-fp/main.c new file mode 100644 index 00000000000..55dab779802 --- /dev/null +++ b/regression/goto-analyzer/precise-array-literal-const-fp/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + fp_tbl[1](); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-array-literal-const-fp/test.desc b/regression/goto-analyzer/precise-array-literal-const-fp/test.desc new file mode 100644 index 00000000000..fad0e6c7a1d --- /dev/null +++ b/regression/goto-analyzer/precise-array-literal-const-fp/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-array-const-variable-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-array-const-variable-const-fp/main.c new file mode 100644 index 00000000000..c2465dcb695 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-const-variable-const-fp/main.c @@ -0,0 +1,33 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const int x = 1; + const void_fp fp = fp_tbl[x]; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-array-const-variable-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-array-const-variable-const-fp/test.desc new file mode 100644 index 00000000000..fad0e6c7a1d --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-const-variable-const-fp/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-array-literal-const-fp-run-time/main.c b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp-run-time/main.c new file mode 100644 index 00000000000..59d51313fde --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp-run-time/main.c @@ -0,0 +1,32 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp_tbl[] = {f2, f3}; + // Illegal: + //fp_tbl[1] = f4; + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main() +{ + func(); + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-array-literal-const-fp-run-time/test.desc b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp-run-time/test.desc new file mode 100644 index 00000000000..6c7de56a1a0 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp-run-time/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-array-literal-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp/main.c new file mode 100644 index 00000000000..2e9cb8cc4df --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp/main.c @@ -0,0 +1,32 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-array-literal-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp/test.desc new file mode 100644 index 00000000000..fad0e6c7a1d --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-literal-const-fp/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-array-literal-const-struct-non-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-array-literal-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..26f13fc4c28 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-literal-const-struct-non-const-fp/main.c @@ -0,0 +1,52 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +struct stable +{ + int x; + void (*fp)(void); +}; + +const struct stable stable_table [3] = +{ + { 1, f2 }, + { 2, f3 }, + { 3, f4 } +}; + +const struct stable another_table = { 4, f5 }; + + +void func(int i) +{ + const void_fp fp = stable_table[1].fp; + + // Illegal + // stable_table[1] = another_table; + // stable_table[1].fp = f5; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-array-literal-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-array-literal-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-literal-const-struct-non-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-array-variable-const-pointer-const-struct-non-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-array-variable-const-pointer-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..c61a7a32499 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-variable-const-pointer-const-struct-non-const-fp/main.c @@ -0,0 +1,49 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct action +{ + int x; + void_fp fun; +}; + +const struct action rec = { .x = 4, .fun = f2 }; + +const struct action * const action_list[4] = +{ + &rec, + &rec, + &rec, + &rec +}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + const void_fp fp = action_list[i]->fun; + fp(); +} + +int main() +{ + for(int i=0;i<4;i++) +{ + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-array-variable-const-pointer-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-array-variable-const-pointer-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..eb1e2781ef1 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-array-variable-const-pointer-const-struct-non-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f2\(\); +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-const-fp/main.c new file mode 100644 index 00000000000..a1efb8e0934 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-fp/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + const void_fp fp2 = fp; + fp2(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-const-fp/test.desc new file mode 100644 index 00000000000..40361f6ccc2 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-fp/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*f2\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-const-struct-const-array-literal-fp/main.c b/regression/goto-analyzer/precise-const-fp-const-struct-const-array-literal-fp/main.c new file mode 100644 index 00000000000..8a05a9b7d4c --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-struct-const-array-literal-fp/main.c @@ -0,0 +1,39 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_container +{ + const void_fp fp_tbl[3]; +} fp_container; + + + +void func() +{ + const fp_container container = { .fp_tbl = {f2 ,f3, f4} }; + const fp_container container2 = { .fp_tbl = {f5 ,f6, f7} }; + // Illegal: + //container = container2; + const void_fp fp = container.fp_tbl[1]; + fp(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/precise-const-fp-const-struct-const-array-literal-fp/test.desc b/regression/goto-analyzer/precise-const-fp-const-struct-const-array-literal-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-struct-const-array-literal-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-const-struct-non-const-array-literal-fp/main.c b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-array-literal-fp/main.c new file mode 100644 index 00000000000..bc4ffead00e --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-array-literal-fp/main.c @@ -0,0 +1,45 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_container +{ + int x; + void_fp fp_tbl[3]; +} fp_container; + + + +void func() +{ + const fp_container container = { .x = 4, .fp_tbl = {f2 ,f3, f4} }; + fp_container container2 = { .x = 5, .fp_tbl = {f5 ,f6, f7} }; + const void_fp alternatate_fp_tbl[] = {f5 ,f6, f7}; + // Illegal: + // container = container2; + // container.fp_tbl = alternatate_fp_tbl; + // container.fp_tbl[1] = f4; + const void_fp fp = container.fp_tbl[1]; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-const-struct-non-const-array-literal-fp/test.desc b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-array-literal-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-array-literal-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-const-struct-non-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..7c3bed93919 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-fp/main.c @@ -0,0 +1,44 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct action +{ + int x; + void_fp fun; +}; + +const struct action rec = { .x = 4, .fun = f2 }; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + + // Illegal: + //rec.fun = &f5; + const void_fp fp = rec.fun; + fp(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..eb1e2781ef1 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-const-struct-non-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f2\(\); +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp-dereference-const-pointer-const-fp/main.c b/regression/goto-analyzer/precise-const-fp-dereference-const-pointer-const-fp/main.c new file mode 100644 index 00000000000..efeb3b35d80 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-dereference-const-pointer-const-fp/main.c @@ -0,0 +1,36 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f3; + const void_fp fp2 = f4; + const void_fp* const p2fp = &fp; + // Illegal: + //p2fp = &fp2; + //fp = f5; + const void_fp final_fp=*p2fp; + final_fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-dereference-const-pointer-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp-dereference-const-pointer-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-dereference-const-pointer-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-fp/main.c b/regression/goto-analyzer/precise-const-fp/main.c new file mode 100644 index 00000000000..b4002c94e5e --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp/main.c @@ -0,0 +1,30 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp/test.desc b/regression/goto-analyzer/precise-const-fp/test.desc new file mode 100644 index 00000000000..ef4cf690b60 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f2\(\); +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-pointer-const-struct-fp/main.c b/regression/goto-analyzer/precise-const-pointer-const-struct-fp/main.c new file mode 100644 index 00000000000..e1671666b2b --- /dev/null +++ b/regression/goto-analyzer/precise-const-pointer-const-struct-fp/main.c @@ -0,0 +1,43 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_cc +{ + int x; + void_fp fp; +} fp_cc; + + + +void func() +{ + const fp_cc container_container = { .fp = f2, .x = 4 }; + + const fp_cc * const container_pointer = &container_container; + + // Illegal: + //meta_fp = &f4; + //container_container.container = &f4; + + container_pointer->fp(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/precise-const-pointer-const-struct-fp/test.desc b/regression/goto-analyzer/precise-const-pointer-const-struct-fp/test.desc new file mode 100644 index 00000000000..0de6942ba42 --- /dev/null +++ b/regression/goto-analyzer/precise-const-pointer-const-struct-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f2\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-const-struct-non-const-fp/main.c b/regression/goto-analyzer/precise-const-struct-non-const-fp/main.c new file mode 100644 index 00000000000..150ea314914 --- /dev/null +++ b/regression/goto-analyzer/precise-const-struct-non-const-fp/main.c @@ -0,0 +1,40 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +struct action +{ + int x; + void_fp fun; +}; + +const struct action rec = { .x = 4, .fun = f2 }; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + rec.fun(); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-struct-non-const-fp/test.desc b/regression/goto-analyzer/precise-const-struct-non-const-fp/test.desc new file mode 100644 index 00000000000..eb1e2781ef1 --- /dev/null +++ b/regression/goto-analyzer/precise-const-struct-non-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f2\(\); +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-derefence-const-pointer-const-fp/main.c b/regression/goto-analyzer/precise-derefence-const-pointer-const-fp/main.c new file mode 100644 index 00000000000..78901cc6405 --- /dev/null +++ b/regression/goto-analyzer/precise-derefence-const-pointer-const-fp/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f3; + const void_fp fp2 = f4; + const void_fp* const p2fp = &fp; + // Illegal: + //p2fp = &fp2; + //fp = f5; + (*p2fp)(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-derefence-const-pointer-const-fp/test.desc b/regression/goto-analyzer/precise-derefence-const-pointer-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-derefence-const-pointer-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-derefence/main.c b/regression/goto-analyzer/precise-derefence/main.c new file mode 100644 index 00000000000..d3bc8a2bc35 --- /dev/null +++ b/regression/goto-analyzer/precise-derefence/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + // There isn't an obvious reason to write this code, but perhaps some + // code can get transformed into this so we should still handle it. + (*(&f2))(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-derefence/test.desc b/regression/goto-analyzer/precise-derefence/test.desc new file mode 100644 index 00000000000..ef4cf690b60 --- /dev/null +++ b/regression/goto-analyzer/precise-derefence/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f2\(\); +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-dereference-address-pointer-const-fp/main.c b/regression/goto-analyzer/precise-dereference-address-pointer-const-fp/main.c new file mode 100644 index 00000000000..e0246369f7b --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-address-pointer-const-fp/main.c @@ -0,0 +1,30 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f3; + (*(&fp))(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-dereference-address-pointer-const-fp/test.desc b/regression/goto-analyzer/precise-dereference-address-pointer-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-address-pointer-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-fp/main.c b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-fp/main.c new file mode 100644 index 00000000000..c8694d74a08 --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-fp/main.c @@ -0,0 +1,42 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_cc +{ + int x; + const void_fp * const container; +} fp_cc; + + + +void func() +{ + const void_fp meta_fp = &f3; + const fp_cc container_container = { .container = &meta_fp, .x = 4 }; + + // Illegal: + //meta_fp = &f4; + //container_container.container = &f4; + + (*container_container.container)(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-fp/test.desc b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-struct-const-fp/main.c b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-struct-const-fp/main.c new file mode 100644 index 00000000000..4f00ca80765 --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-struct-const-fp/main.c @@ -0,0 +1,49 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_container +{ + int y; + const void_fp pointer; +} fp_container; + +typedef struct fp_cc +{ + int x; + const fp_container * const container; +} fp_cc; + + + +void func() +{ + const fp_container container = {.y = 10, .pointer = f3}; + const fp_container container2 = {.y = 10, .pointer = f4}; + const fp_cc container_container = { .container = &container, .x = 4 }; + + // Illegal: + //container_container.container = &container2; + //container.pointer = f4; + + (*container_container.container).pointer(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-struct-const-fp/test.desc b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-struct-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-const-struct-const-pointer-const-struct-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/precise-dereference-const-struct-pointer-const-fp/main.c b/regression/goto-analyzer/precise-dereference-const-struct-pointer-const-fp/main.c new file mode 100644 index 00000000000..1d562a42dc8 --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-const-struct-pointer-const-fp/main.c @@ -0,0 +1,42 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +typedef struct fp_cc +{ + int x; + const void_fp * container; +} fp_cc; + + + +void func() +{ + const void_fp meta_fp = &f3; + const fp_cc container_container = { .container = &meta_fp, .x = 4 }; + + // Illegal: + //meta_fp = &f4; + //container_container.container = &f4; + + (*container_container.container)(); +} + +int main() +{ + func(); +} diff --git a/regression/goto-analyzer/precise-dereference-const-struct-pointer-const-fp/test.desc b/regression/goto-analyzer/precise-dereference-const-struct-pointer-const-fp/test.desc new file mode 100644 index 00000000000..2eff811f4bc --- /dev/null +++ b/regression/goto-analyzer/precise-dereference-const-struct-pointer-const-fp/test.desc @@ -0,0 +1,9 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check + +^Removing function pointers and virtual functions$ +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/approx-array-variable-const-fp-only-remove-const/main.c b/regression/goto-instrument/approx-array-variable-const-fp-only-remove-const/main.c new file mode 100644 index 00000000000..3fb230c83fd --- /dev/null +++ b/regression/goto-instrument/approx-array-variable-const-fp-only-remove-const/main.c @@ -0,0 +1,34 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + fp_tbl[i](); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} \ No newline at end of file diff --git a/regression/goto-instrument/approx-array-variable-const-fp-only-remove-const/test.desc b/regression/goto-instrument/approx-array-variable-const-fp-only-remove-const/test.desc new file mode 100644 index 00000000000..f58b03a58b3 --- /dev/null +++ b/regression/goto-instrument/approx-array-variable-const-fp-only-remove-const/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--verbosity 10 --pointer-check --remove-const-function-pointers + +^\s*IF fp_tbl\[\(signed long int\)i\] == f2 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f3 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ +^warning: ignoring diff --git a/regression/goto-instrument/approx-array-variable-const-fp-remove-all-fp/main.c b/regression/goto-instrument/approx-array-variable-const-fp-remove-all-fp/main.c new file mode 100644 index 00000000000..7896e3402c0 --- /dev/null +++ b/regression/goto-instrument/approx-array-variable-const-fp-remove-all-fp/main.c @@ -0,0 +1,34 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +const void_fp fp_tbl[] = {f2, f3 ,f4}; + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i) +{ + fp_tbl[i](); +} + +int main() +{ + for(int i=0;i<3;i++) + { + func(i); + } + + return 0; +} diff --git a/regression/goto-instrument/approx-array-variable-const-fp-remove-all-fp/test.desc b/regression/goto-instrument/approx-array-variable-const-fp-remove-all-fp/test.desc new file mode 100644 index 00000000000..3d065f1a742 --- /dev/null +++ b/regression/goto-instrument/approx-array-variable-const-fp-remove-all-fp/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--verbosity 10 --pointer-check --remove-function-pointers + +^\s*IF fp_tbl\[\(signed long int\)i\] == f2 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f3 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f4 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^\s*IF fp_tbl\[\(signed long int\)i\] == f1 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f5 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f6 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f7 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f8 THEN GOTO [0-9]$ +^\s*IF fp_tbl\[\(signed long int\)i\] == f9 THEN GOTO [0-9]$ +^warning: ignoring diff --git a/regression/goto-instrument/no-match-non-const-fp-only-remove-const/main.c b/regression/goto-instrument/no-match-non-const-fp-only-remove-const/main.c new file mode 100644 index 00000000000..80c8c863ff5 --- /dev/null +++ b/regression/goto-instrument/no-match-non-const-fp-only-remove-const/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp fp = f2; + fp = f3; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-instrument/no-match-non-const-fp-only-remove-const/test.desc b/regression/goto-instrument/no-match-non-const-fp-only-remove-const/test.desc new file mode 100644 index 00000000000..3b016907a44 --- /dev/null +++ b/regression/goto-instrument/no-match-non-const-fp-only-remove-const/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--verbosity 10 --pointer-check --remove-const-function-pointers + +^\s*fp\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/no-match-non-const-fp-remove-all-fp/main.c b/regression/goto-instrument/no-match-non-const-fp-remove-all-fp/main.c new file mode 100644 index 00000000000..80c8c863ff5 --- /dev/null +++ b/regression/goto-instrument/no-match-non-const-fp-remove-all-fp/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp fp = f2; + fp = f3; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-instrument/no-match-non-const-fp-remove-all-fp/test.desc b/regression/goto-instrument/no-match-non-const-fp-remove-all-fp/test.desc new file mode 100644 index 00000000000..3190d348aae --- /dev/null +++ b/regression/goto-instrument/no-match-non-const-fp-remove-all-fp/test.desc @@ -0,0 +1,16 @@ +CORE +main.c +--verbosity 10 --pointer-check --remove-function-pointers + +^\s*IF fp == f1 THEN GOTO [0-9]$ +^\s*IF fp == f2 THEN GOTO [0-9]$ +^\s*IF fp == f3 THEN GOTO [0-9]$ +^\s*IF fp == f4 THEN GOTO [0-9]$ +^\s*IF fp == f5 THEN GOTO [0-9]$ +^\s*IF fp == f6 THEN GOTO [0-9]$ +^\s*IF fp == f7 THEN GOTO [0-9]$ +^\s*IF fp == f8 THEN GOTO [0-9]$ +^\s*IF fp == f9 THEN GOTO [0-9]$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-instrument/precise-const-fp-only-remove-const/main.c b/regression/goto-instrument/precise-const-fp-only-remove-const/main.c new file mode 100644 index 00000000000..b4002c94e5e --- /dev/null +++ b/regression/goto-instrument/precise-const-fp-only-remove-const/main.c @@ -0,0 +1,30 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-instrument/precise-const-fp-only-remove-const/test.desc b/regression/goto-instrument/precise-const-fp-only-remove-const/test.desc new file mode 100644 index 00000000000..2304d56b239 --- /dev/null +++ b/regression/goto-instrument/precise-const-fp-only-remove-const/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--verbosity 10 --pointer-check --remove-const-function-pointers + +^\s*f2\(\); +-- +^warning: ignoring diff --git a/regression/goto-instrument/precise-const-fp-remove-all-fp/main.c b/regression/goto-instrument/precise-const-fp-remove-all-fp/main.c new file mode 100644 index 00000000000..b4002c94e5e --- /dev/null +++ b/regression/goto-instrument/precise-const-fp-remove-all-fp/main.c @@ -0,0 +1,30 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-instrument/precise-const-fp-remove-all-fp/test.desc b/regression/goto-instrument/precise-const-fp-remove-all-fp/test.desc new file mode 100644 index 00000000000..dd072b1c232 --- /dev/null +++ b/regression/goto-instrument/precise-const-fp-remove-all-fp/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--verbosity 10 --pointer-check --remove-function-pointers + +^\s*f2\(\); +-- +^warning: ignoring diff --git a/src/analyses/Makefile b/src/analyses/Makefile index 89f14e4f768..e05d5be0c42 100644 --- a/src/analyses/Makefile +++ b/src/analyses/Makefile @@ -6,7 +6,9 @@ SRC = natural_loops.cpp is_threaded.cpp dirty.cpp interval_analysis.cpp \ local_bitvector_analysis.cpp dependence_graph.cpp \ constant_propagator.cpp replace_symbol_ext.cpp \ flow_insensitive_analysis.cpp \ - custom_bitvector_analysis.cpp escape_analysis.cpp global_may_alias.cpp + custom_bitvector_analysis.cpp escape_analysis.cpp global_may_alias.cpp \ + does_remove_const.cpp \ + # Empty last line INCLUDES= -I .. diff --git a/src/analyses/does_remove_const.cpp b/src/analyses/does_remove_const.cpp new file mode 100644 index 00000000000..fcccd8219c9 --- /dev/null +++ b/src/analyses/does_remove_const.cpp @@ -0,0 +1,167 @@ +/*******************************************************************\ + + Module: Analyses + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "does_remove_const.h" + +/*******************************************************************\ + +Function: does_remove_constt::does_remove_constt + + Inputs: + goto_program - the goto program to check + ns - the namespace of the goto program (used for checking type equality) + + Outputs: + + Purpose: A naive analysis to look for casts that remove const-ness from + pointers. + +\*******************************************************************/ + +does_remove_constt::does_remove_constt( + const goto_programt &goto_program, + const namespacet &ns): + goto_program(goto_program), + ns(ns) +{} + +/*******************************************************************\ + +Function: does_remove_constt::operator() + + Inputs: + + Outputs: Returns true if the program contains a const-removing cast + + Purpose: A naive analysis to look for casts that remove const-ness from + pointers. + +\*******************************************************************/ + +bool does_remove_constt::operator()() const +{ + for(const goto_programt::instructiont &instruction : + goto_program.instructions) + { + if(!instruction.is_assign()) + { + continue; + } + + const code_assignt &assign=to_code_assign(instruction.code); + const typet &rhs_type=assign.rhs().type(); + const typet &lhs_type=assign.lhs().type(); + + // Compare the types recursively for a point where the rhs is more + // const that the lhs + if(!is_type_at_least_as_const_as(&lhs_type, &rhs_type)) + { + return true; + } + + if(does_expr_lose_const(assign.rhs())) + { + return true; + } + } + + return false; +} + +/*******************************************************************\ + +Function: does_remove_constt::does_expr_lose_const() + + Inputs: + expr - The expression to check + + Outputs: Returns true if somewhere in the passed expression tree the const-ness + is lost. + + Purpose: Search the expression tree to look for any children that have the + same base type, but a less strict const qualification. + If one is found, we return true. + +\*******************************************************************/ + +bool does_remove_constt::does_expr_lose_const(const exprt &expr) const +{ + const typet &root_type=expr.type(); + + // Look in each child that has the same base type as the root + for(const exprt &op : expr.operands()) + { + const typet &op_type=op.type(); + if(base_type_eq(op_type, root_type, ns)) + { + // Is this child more const-qualified than the root + if(!is_type_at_least_as_const_as(&root_type, &op_type)) + { + return true; + } + } + + // Recursively check the children of this child + if(does_expr_lose_const(op)) + { + return true; + } + } + return false; +} + +/*******************************************************************\ + +Function: does_remove_constt::is_type_at_least_as_const_as + + Inputs: + type_more_const - the type we are expecting to be at least as const qualified + type_compare - the type we are comparing against which may be less const + qualified + + Outputs: Returns true if type_more_const is at least as const as type_compare + + Purpose: A recursive check to check the type_more_const is at least as const + as type compare. + + type_more_const | type_compare || result + ---------------------------------------- + const int * | const int * -> true + int * | const int * -> false + const int * | int * -> true + int * | int * const -> false + +\*******************************************************************/ + +bool does_remove_constt::is_type_at_least_as_const_as( + const typet *type_more_const, const typet *type_compare) const +{ + while(type_compare->id()!=ID_nil && type_more_const->id()!=ID_nil) + { + const c_qualifierst rhs_qualifiers(*type_compare); + const c_qualifierst lhs_qualifiers(*type_more_const); + if(rhs_qualifiers.is_constant && !lhs_qualifiers.is_constant) + { + return false; + } + + type_compare=&type_compare->subtype(); + type_more_const=&type_more_const->subtype(); + } + + // Both the types should have the same number of subtypes + assert(type_compare->id()==ID_nil && type_more_const->id()==ID_nil); + return true; +} diff --git a/src/analyses/does_remove_const.h b/src/analyses/does_remove_const.h new file mode 100644 index 00000000000..594682c7d50 --- /dev/null +++ b/src/analyses/does_remove_const.h @@ -0,0 +1,31 @@ +/*******************************************************************\ + + Module: Analyses + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_DOES_REMOVE_CONST_H +#define CPROVER_ANALYSES_DOES_REMOVE_CONST_H + +#include + +class goto_programt; + +class does_remove_constt +{ +public: + does_remove_constt(const goto_programt &goto_program, const namespacet &ns); + bool operator()() const; + +private: + bool does_expr_lose_const(const exprt &expr) const; + + bool is_type_at_least_as_const_as( + const typet *type_more_const, const typet *type_compare) const; + + const goto_programt &goto_program; + const namespacet &ns; +}; + +#endif // CPROVER_ANALYSES_DOES_REMOVE_CONST_H diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index 657e4531429..8bbdb8ce89e 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -877,6 +877,7 @@ bool cbmc_parse_optionst::process_goto_program( // remove function pointers status() << "Removal of function pointers and virtual functions" << eom; remove_function_pointers( + get_message_handler(), symbol_table, goto_functions, cmdline.isset("pointer-check")); diff --git a/src/goto-analyzer/goto_analyzer_parse_options.cpp b/src/goto-analyzer/goto_analyzer_parse_options.cpp index e462740c1cc..9a74e27f167 100644 --- a/src/goto-analyzer/goto_analyzer_parse_options.cpp +++ b/src/goto-analyzer/goto_analyzer_parse_options.cpp @@ -385,7 +385,8 @@ bool goto_analyzer_parse_optionst::process_goto_program( // remove function pointers status() << "Removing function pointers and virtual functions" << eom; - remove_function_pointers(goto_model, cmdline.isset("pointer-check")); + remove_function_pointers( + get_message_handler(), goto_model, cmdline.isset("pointer-check")); // Java virtual functions -> explicit dispatch tables: remove_virtual_functions(goto_model); // remove Java throw and catch @@ -540,6 +541,9 @@ void goto_analyzer_parse_optionst::help() // NOLINTNEXTLINE(whitespace/line_length) " --show-properties show the properties, but don't run analysis\n" "\n" + "Program instrumentation options:\n" + HELP_GOTO_CHECK + "\n" "Other options:\n" " --version show version and exit\n" "\n"; diff --git a/src/goto-analyzer/goto_analyzer_parse_options.h b/src/goto-analyzer/goto_analyzer_parse_options.h index 7b319c8b99b..caf95254288 100644 --- a/src/goto-analyzer/goto_analyzer_parse_options.h +++ b/src/goto-analyzer/goto_analyzer_parse_options.h @@ -17,6 +17,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include + class bmct; class goto_functionst; class optionst; @@ -28,6 +30,7 @@ class optionst; "(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ "(little-endian)(big-endian)" \ OPT_SHOW_GOTO_FUNCTIONS \ + OPT_GOTO_CHECK \ "(show-loops)" \ "(show-symbol-table)(show-parse-tree)" \ "(show-properties)(show-reachable-properties)(property):" \ diff --git a/src/goto-diff/goto_diff_parse_options.cpp b/src/goto-diff/goto_diff_parse_options.cpp index a405178652f..b86eee9fea1 100644 --- a/src/goto-diff/goto_diff_parse_options.cpp +++ b/src/goto-diff/goto_diff_parse_options.cpp @@ -487,6 +487,7 @@ bool goto_diff_parse_optionst::process_goto_program( // remove function pointers status() << "Function Pointer Removal" << eom; remove_function_pointers( + get_message_handler(), symbol_table, goto_functions, cmdline.isset("pointer-check")); diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index b5486355277..7af3323d8e8 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -806,6 +806,7 @@ void goto_instrument_parse_optionst::do_indirect_call_and_rtti_removal( status() << "Function Pointer Removal" << eom; remove_function_pointers( + get_message_handler(), symbol_table, goto_functions, cmdline.isset("pointer-check")); @@ -819,6 +820,39 @@ void goto_instrument_parse_optionst::do_indirect_call_and_rtti_removal( /*******************************************************************\ +Function: goto_instrument_parse_optionst::do_remove_const_function_pointers_only + + Inputs: + + Outputs: + + Purpose: Remove function pointers that can be resolved by analysing + const variables (i.e. can be resolved using + remove_const_function_pointers). Function pointers that cannot + be resolved will be left as function pointers. + +\*******************************************************************/ + +void goto_instrument_parse_optionst::do_remove_const_function_pointers_only() +{ + // Don't bother if we've already done a full function pointer + // removal. + if(function_pointer_removal_done) + { + return; + } + + status() << "Removing const function pointers only" << eom; + remove_function_pointers( + get_message_handler(), + symbol_table, + goto_functions, + cmdline.isset("pointer-check"), + true); // abort if we can't resolve via const pointers +} + +/*******************************************************************\ + Function: goto_instrument_parse_optionst::do_partial_inlining Inputs: @@ -1045,7 +1079,13 @@ void goto_instrument_parse_optionst::instrument_goto_program() // replace function pointers, if explicitly requested if(cmdline.isset("remove-function-pointers")) + { do_indirect_call_and_rtti_removal(); + } + else if(cmdline.isset("remove-const-function-pointers")) + { + do_remove_const_function_pointers_only(); + } if(cmdline.isset("function-inline")) { @@ -1555,6 +1595,7 @@ void goto_instrument_parse_optionst::help() " --no-caching disable caching of intermediate results during transitive function inlining\n" // NOLINT(*) " --log log in json format which code segments were inlined, use with --function-inline\n" // NOLINT(*) " --remove-function-pointers replace function pointers by case statement over function calls\n" // NOLINT(*) + HELP_REMOVE_CONST_FUNCTION_POINTERS " --add-library add models of C library functions\n" " --model-argc-argv model up to command line arguments\n" "\n" diff --git a/src/goto-instrument/goto_instrument_parse_options.h b/src/goto-instrument/goto_instrument_parse_options.h index d3efb975767..d4054b6e0a4 100644 --- a/src/goto-instrument/goto_instrument_parse_options.h +++ b/src/goto-instrument/goto_instrument_parse_options.h @@ -15,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include @@ -54,6 +55,7 @@ Author: Daniel Kroening, kroening@kroening.com "(show-uninitialized)(show-locations)" \ "(full-slice)(reachability-slice)(slice-global-inits)" \ "(inline)(partial-inline)(function-inline):(log):(no-caching)" \ + OPT_REMOVE_CONST_FUNCTION_POINTERS \ "(remove-function-pointers)" \ "(show-claims)(show-properties)(property):" \ "(show-symbol-table)(show-points-to)(show-rw-set)" \ @@ -98,6 +100,7 @@ class goto_instrument_parse_optionst: void eval_verbosity(); void do_indirect_call_and_rtti_removal(bool force=false); + void do_remove_const_function_pointers_only(); void do_partial_inlining(); void do_remove_returns(); diff --git a/src/goto-programs/Makefile b/src/goto-programs/Makefile index d5cc5ea25eb..bf6abb39ab6 100644 --- a/src/goto-programs/Makefile +++ b/src/goto-programs/Makefile @@ -20,7 +20,9 @@ SRC = goto_convert.cpp goto_convert_function_call.cpp \ slice_global_inits.cpp goto_inline_class.cpp class_identifier.cpp \ show_goto_functions_json.cpp \ show_goto_functions_xml.cpp \ - remove_static_init_loops.cpp remove_instanceof.cpp + remove_static_init_loops.cpp remove_instanceof.cpp \ + remove_const_function_pointers.cpp \ + # Empty last line INCLUDES= -I .. diff --git a/src/goto-programs/remove_const_function_pointers.cpp b/src/goto-programs/remove_const_function_pointers.cpp new file mode 100644 index 00000000000..c0a7d8d5380 --- /dev/null +++ b/src/goto-programs/remove_const_function_pointers.cpp @@ -0,0 +1,1007 @@ +/*******************************************************************\ + +Module: Goto Programs + +Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include +#include +#include + +#include "remove_const_function_pointers.h" + +#define LOG(message, irep) \ + debug() << "Case " << __LINE__ << " : " << message << "\n" \ + << irep.pretty() << eom; + +/*******************************************************************\ + +Function: remove_const_function_pointerst::remove_const_function_pointerst + + Inputs: + message_handler - The message handler for messaget + base_expression - The function call through a function pointer + ns - The namespace to use to resolve types + symbol_table - The symbol table to look up symbols in + + Outputs: + + Purpose: To take a function call on a function pointer, and if possible + resolve it to a small collection of possible values. + +\*******************************************************************/ + +remove_const_function_pointerst::remove_const_function_pointerst( + message_handlert &message_handler, + const exprt &base_expression, + const namespacet &ns, + const symbol_tablet &symbol_table): + messaget(message_handler), + original_expression(base_expression), + ns(ns), + symbol_table(symbol_table) +{} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::operator() + + Inputs: + out_functions - The functions that (symbols of type ID_code) the base + expression could take. + + Outputs: Returns true if it was able to resolve the call, false if not. + If it returns true, out_functions will be populated by all the + possible values the function pointer could be. + + Purpose: To take a function call on a function pointer, and if possible + resolve it to a small collection of possible values. It will + resolve function pointers that are const and: + - assigned directly to a function + - assigned to a value in an array of functions + - assigned to a const struct component + Or variations within. + +\*******************************************************************/ + +bool remove_const_function_pointerst::operator()( + functionst &out_functions) +{ + // Replace all const symbols with their values + exprt non_symbol_expression=replace_const_symbols(original_expression); + return try_resolve_function_call(non_symbol_expression, out_functions); +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::replace_const_symbols + + Inputs: + expression - The expression to resolve symbols in + + Outputs: Returns a modified version of the expression, with all + const symbols resolved to their actual values. + + Purpose: To collapse the symbols down to their values where possible + This takes a very general approach, recreating the expr tree + exactly as it was and ignoring what type of expressions are found + and instead recurses over all the operands. + +\*******************************************************************/ + +exprt remove_const_function_pointerst::replace_const_symbols( + const exprt &expression) const +{ + if(expression.id()==ID_symbol) + { + if(is_const_expression(expression)) + { + const symbolt &symbol= + symbol_table.lookup(expression.get(ID_identifier)); + if(symbol.type.id()!=ID_code) + { + const exprt &symbol_value=symbol.value; + return replace_const_symbols(symbol_value); + } + else + { + return expression; + } + } + else + { + return expression; + } + } + else + { + exprt const_symbol_cleared_expr=expression; + const_symbol_cleared_expr.operands().clear(); + for(const exprt &op : expression.operands()) + { + exprt const_symbol_cleared_op=replace_const_symbols(op); + const_symbol_cleared_expr.operands().push_back(const_symbol_cleared_op); + } + + return const_symbol_cleared_expr; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::resolve_symbol + + Inputs: + symbol_expr - The symbol expression + + Outputs: The expression value of the symbol. + + Purpose: Look up a symbol in the symbol table and return its value + +\*******************************************************************/ + +exprt remove_const_function_pointerst::resolve_symbol( + const symbol_exprt &symbol_expr) const +{ + const symbolt &symbol= + symbol_table.lookup(symbol_expr.get_identifier()); + return symbol.value; +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_function_call + + Inputs: + expr - The expression to get the possible function calls + out_functions - The functions this expression could be resolved to + + Outputs: Returns true if it was able to resolve the expression to some + specific functions. If this is the case, out_functions will contain + the possible functions. + + Purpose: To resolve an expression to the specific function calls it can + be. This is different to try_resolve_expression which isn't + explicitly looking for functions and is instead just trying + to squash particular exprt structures. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_function_call( + const exprt &expr, functionst &out_functions) +{ + assert(out_functions.empty()); + const exprt &simplified_expr=simplify_expr(expr, ns); + bool resolved=false; + functionst resolved_functions; + if(simplified_expr.id()==ID_index) + { + const index_exprt &index_expr=to_index_expr(simplified_expr); + resolved=try_resolve_index_of_function_call(index_expr, resolved_functions); + } + else if(simplified_expr.id()==ID_member) + { + const member_exprt &member_expr=to_member_expr(simplified_expr); + resolved=try_resolve_member_function_call(member_expr, resolved_functions); + } + else if(simplified_expr.id()==ID_address_of) + { + address_of_exprt address_expr=to_address_of_expr(simplified_expr); + resolved=try_resolve_address_of_function_call( + address_expr, resolved_functions); + } + else if(simplified_expr.id()==ID_dereference) + { + const dereference_exprt &deref=to_dereference_expr(simplified_expr); + resolved=try_resolve_dereference_function_call(deref, resolved_functions); + } + else if(simplified_expr.id()==ID_typecast) + { + typecast_exprt typecast_expr=to_typecast_expr(simplified_expr); + resolved= + try_resolve_typecast_function_call(typecast_expr, resolved_functions); + } + else if(simplified_expr.id()==ID_symbol) + { + if(simplified_expr.type().id()==ID_code) + { + resolved_functions.insert(simplified_expr); + resolved=true; + } + else + { + LOG("Non const symbol wasn't squashed", simplified_expr); + resolved=false; + } + } + else + { + LOG("Unrecognised expression", simplified_expr); + resolved=false; + } + + if(resolved) + { + out_functions.insert(resolved_functions.begin(), resolved_functions.end()); + return true; + } + else + { + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_function_calls + + Inputs: + exprs - The expressions to evaluate + out_functions - The functions these expressions resolve to + + Outputs: Returns true if able to resolve each of the expressions down + to one or more functions. + + Purpose: To resolve a collection of expressions to the specific function + calls they can be. Returns a collection if and only if all of + them can be resolved. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_function_calls( + const expressionst &exprs, functionst &out_functions) +{ + for(const exprt &value : exprs) + { + functionst potential_out_functions; + bool resolved_value= + try_resolve_function_call(value, potential_out_functions); + + if(resolved_value) + { + out_functions.insert( + potential_out_functions.begin(), + potential_out_functions.end()); + } + else + { + LOG("Could not resolve expression in array", value); + return false; + } + } + return true; +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_index_of_function_call + + Inputs: + index_expr - The index expression to resolve to possible function calls + out_functions - The functions this expression could be + + Outputs: Returns true if it was able to resolve the index expression to some + specific functions. If this is the case, out_functions will contain + the possible functions. + + Purpose: To resolve an expression to the specific function calls it can + be. Specifically, this function deals with index expressions + where it squashes its array and squash its index + If we can get a precise number for the index, we + try_resolve_function_call on its value otherwise + try_resolve_function_call on each and return the union of them all + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_index_of_function_call( + const index_exprt &index_expr, functionst &out_functions) +{ + expressionst potential_array_values; + bool array_const; + bool resolved= + try_resolve_index_of(index_expr, potential_array_values, array_const); + + if(!resolved) + { + LOG("Could not resolve array", index_expr); + return false; + } + + if(!array_const) + { + LOG("Array not const", index_expr); + return false; + } + + return try_resolve_function_calls(potential_array_values, out_functions); +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_member_function_call + + Inputs: + member_expr - The member expression to resolve to possible function calls + out_functions - The functions this expression could be + + Outputs: Returns true if it was able to resolve the member expression to some + specific functions. If this is the case, out_functions will contain + the possible functions. + + Purpose: To resolve an expression to the specific function calls it can + be. Specifically, this function deals with member expressions + by using try_resolve_member and then recursing on its value. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_member_function_call( + const member_exprt &member_expr, functionst &out_functions) +{ + expressionst potential_component_values; + bool struct_const; + bool resolved= + try_resolve_member(member_expr, potential_component_values, struct_const); + + if(!resolved) + { + LOG("Could not resolve struct", member_expr); + return false; + } + + if(!struct_const) + { + LOG("Struct was not const so can't resolve values on it", member_expr); + return false; + } + + return try_resolve_function_calls(potential_component_values, out_functions); +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_address_of_function_call + + Inputs: + address_expr - The address_of expression to resolve to possible function + calls + out_functions - The functions this expression could be + + Outputs: Returns true if it was able to resolve the address_of expression to + some specific functions. If this is the case, out_functions will + contain the possible functions. + + Purpose: To resolve an expression to the specific function calls it can + be. Specifically, this function deals with address_of expressions. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_address_of_function_call( + const address_of_exprt &address_expr, functionst &out_functions) +{ + bool resolved= + try_resolve_function_call(address_expr.object(), out_functions); + if(!resolved) + { + LOG("Failed to resolve address of", address_expr); + } + return resolved; +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_dereference_function_call + + Inputs: + deref_expr - The dereference expression to resolve to possible function calls + out_functions - The functions this expression could be + + Outputs: Returns true if it was able to resolve the dereference expression to + some specific functions. If this is the case, out_functions will + contain the possible functions. + + Purpose: To resolve an expression to the specific function calls it can + be. Specifically, this function deals with dereference expressions + by using try_resolve_dereferebce and then recursing on its value. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_dereference_function_call( + const dereference_exprt &deref_expr, functionst &out_functions) +{ + expressionst potential_deref_values; + bool deref_const; + bool resolved= + try_resolve_dereference(deref_expr, potential_deref_values, deref_const); + + if(!resolved) + { + LOG("Failed to squash dereference", deref_expr); + return false; + } + + if(!deref_const) + { + LOG("Dereferenced value was not const so can't dereference", deref_expr); + return false; + } + + return try_resolve_function_calls(potential_deref_values, out_functions); +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_typecast_function_call + + Inputs: + typecast_expr - The typecast expression to resolve to possible function calls + out_functions - The functions this expression could be + + Outputs: Returns true if it was able to resolve the typecast expression to + some specific functions. If this is the case, out_functions will + contain the possible functions. + + Purpose: To resolve an expression to the specific function calls it can + be. Specifically, this function deals with typecast expressions + by looking at the type cast values. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_typecast_function_call( + const typecast_exprt &typecast_expr, functionst &out_functions) +{ + // We simply ignore typecasts and assume they are valid + // I thought simplify_expr would deal with this, but for example + // a cast from a 32 bit width int to a 64bit width int it doesn't seem + // to allow + functionst typecast_values; + bool resolved= + try_resolve_function_call(typecast_expr.op(), typecast_values); + + if(resolved) + { + out_functions.insert(typecast_values.begin(), typecast_values.end()); + return true; + } + else + { + LOG("Failed to squash typecast", typecast_expr); + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_expression + + Inputs: + expr - The expression to try and squash + out_resolved_expression - The squashed version of this expression + out_is_const - Is the squashed expression constant + + Outputs: Returns true providing the squashing went OK (note it + may not have squashed anything). The out_resolved_expression will in + this case be all the possible squashed versions of the supplied + expression. + The out_is_const will return whether the squashed value is suitably + const (e.g. if we squashed a struct access, was the struct const). + + Purpose: To squash various expr types to simplify the expression. + ID_index -> dig to find ID_array and get the values out of it + ID_member -> dig to find ID_struct and extract the component value + ID_dereference -> dig to find ID_address_of and extract the value + ID_typecast -> return the value + ID_symbol -> return false, const symbols are squashed first and + non const symbols cannot be squashed + Everything else -> unchanged + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_expression( + const exprt &expr, expressionst &out_resolved_expression, bool &out_is_const) +{ + exprt simplified_expr=simplify_expr(expr, ns); + bool resolved; + expressionst resolved_expressions; + bool is_resolved_expression_const; + if(simplified_expr.id()==ID_index) + { + const index_exprt &index_expr=to_index_expr(simplified_expr); + resolved= + try_resolve_index_of( + index_expr, resolved_expressions, is_resolved_expression_const); + } + else if(simplified_expr.id()==ID_member) + { + const member_exprt &member_expr=to_member_expr(simplified_expr); + resolved=try_resolve_member( + member_expr, resolved_expressions, is_resolved_expression_const); + } + else if(simplified_expr.id()==ID_dereference) + { + const dereference_exprt &deref=to_dereference_expr(simplified_expr); + resolved= + try_resolve_dereference( + deref, resolved_expressions, is_resolved_expression_const); + } + else if(simplified_expr.id()==ID_typecast) + { + typecast_exprt typecast_expr=to_typecast_expr(simplified_expr); + resolved= + try_resolve_typecast( + typecast_expr, resolved_expressions, is_resolved_expression_const); + } + else if(simplified_expr.id()==ID_symbol) + { + LOG("Non const symbol will not be squashed", simplified_expr); + resolved=false; + } + else + { + resolved_expressions.push_back(simplified_expr); + is_resolved_expression_const=is_const_expression(simplified_expr); + resolved=true; + } + + if(resolved) + { + out_resolved_expression.insert( + out_resolved_expression.end(), + resolved_expressions.begin(), + resolved_expressions.end()); + out_is_const=is_resolved_expression_const; + return true; + } + else + { + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_index_value + + Inputs: + expr - The expression of the index of the index expression (e.g. + index_exprt::index()) + out_array_index - The constant value the index takes + + Outputs: Returns true if was able to find a constant value for the index + expression. If true, then out_array_index will be the index within + the array that the function pointer is pointing to. + + Purpose: Given an index into an array, resolve, if possible, the index + that is being accessed. This deals with symbols and typecasts to + constant values. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_index_value( + const exprt &expr, mp_integer &out_array_index) +{ + expressionst index_value_expressions; + bool is_const=false; + bool resolved=try_resolve_expression(expr, index_value_expressions, is_const); + if(resolved) + { + if(index_value_expressions.size()==1 && + index_value_expressions.front().id()==ID_constant) + { + const constant_exprt &constant_expr= + to_constant_expr(index_value_expressions.front()); + mp_integer array_index; + bool errors=to_integer(constant_expr, array_index); + if(!errors) + { + out_array_index=array_index; + } + return !errors; + } + else + { + return false; + } + } + else + { + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_index_of + + Inputs: + index_expr - The index expression to to resolve + out_expressions - The expressions this expression could be + out_is_const - Is the squashed expression constant + + Outputs: Returns true if it was able to squash the index expression + If this is the case, out_expressions will contain + the possible values this index_of could return + The out_is_const will return whether either the array itself + is const, or the values of the array are const. + + Purpose: To squash an index access by first finding the array it is accessing + Then if the index can be resolved, return the squashed value. If + the index can't be determined then squash each value in the array + and return them all. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_index_of( + const index_exprt &index_expr, + expressionst &out_expressions, + bool &out_is_const) +{ + // Get the array(s) it belongs to + expressionst potential_array_exprs; + bool array_const=false; + bool resolved_array= + try_resolve_expression( + index_expr.array(), + potential_array_exprs, + array_const); + + if(resolved_array) + { + bool all_possible_const=true; + for(const exprt &potential_array_expr : potential_array_exprs) + { + all_possible_const= + all_possible_const && + is_const_type(potential_array_expr.type().subtype()); + + if(potential_array_expr.id()==ID_array) + { + // Get the index if we can + mp_integer value; + if(try_resolve_index_value(index_expr.index(), value)) + { + expressionst array_out_functions; + const exprt &func_expr= + potential_array_expr.operands()[integer2size_t(value)]; + bool value_const=false; + bool resolved_value= + try_resolve_expression(func_expr, array_out_functions, value_const); + + if(resolved_value) + { + out_expressions.insert( + out_expressions.end(), + array_out_functions.begin(), + array_out_functions.end()); + } + else + { + LOG("Failed to resolve array value", func_expr); + return false; + } + } + else + { + // We don't know what index it is, + // but we know the value is from the array + for(const exprt &array_entry : potential_array_expr.operands()) + { + expressionst array_contents; + bool is_entry_const; + bool resolved_value= + try_resolve_expression( + array_entry, array_contents, is_entry_const); + + if(!resolved_value) + { + LOG("Failed to resolve array value", array_entry); + return false; + } + + for(const exprt &resolved_array_entry : array_contents) + { + if(!resolved_array_entry.is_zero()) + { + out_expressions.push_back(resolved_array_entry); + } + } + } + } + } + else + { + LOG( + "Squashing index of did not result in an array", + potential_array_expr); + return false; + } + } + + out_is_const=all_possible_const || array_const; + return true; + } + else + { + LOG("Failed to squash index of to array expression", index_expr); + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_member + + Inputs: + member_expr - The member expression to resolve. + out_expressions - The expressions this component could be + out_is_const - Is the squashed expression constant + + Outputs: Returns true if it was able to squash the member expression + If this is the case, out_expressions will contain + the possible values this member could return + The out_is_const will return whether the struct + is const. + + Purpose: To squash an member access by first finding the struct it is accessing + Then return the squashed value of the relevant component. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_member( + const member_exprt &member_expr, + expressionst &out_expressions, + bool &out_is_const) +{ + expressionst potential_structs; + bool is_struct_const; + + // Get the struct it belongs to + bool resolved_struct= + try_resolve_expression( + member_expr.compound(), potential_structs, is_struct_const); + if(resolved_struct) + { + for(const exprt &potential_struct : potential_structs) + { + if(potential_struct.id()==ID_struct) + { + struct_exprt struct_expr=to_struct_expr(potential_struct); + const exprt &component_value= + get_component_value(struct_expr, member_expr); + expressionst resolved_expressions; + bool component_const=false; + bool resolved= + try_resolve_expression( + component_value, resolved_expressions, component_const); + if(resolved) + { + out_expressions.insert( + out_expressions.end(), + resolved_expressions.begin(), + resolved_expressions.end()); + } + else + { + LOG("Could not resolve component value", component_value); + return false; + } + } + else + { + LOG( + "Squashing member access did not resolve in a struct", + potential_struct); + return false; + } + } + out_is_const=is_struct_const; + return true; + } + else + { + LOG("Failed to squash struct access", member_expr); + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_dereference + + Inputs: + deref_expr - The dereference expression to resolve. + out_expressions - The expressions this dereference could be + out_is_const - Is the squashed expression constant + + Outputs: Returns true if it was able to squash the dereference expression + If this is the case, out_expressions will contain + the possible values this dereference could return + The out_is_const will return whether the object that gets + dereferenced is constant. + + Purpose: To squash a dereference access by first finding the address_of + the dereference is dereferencing. + Then return the squashed value of the relevant component. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_dereference( + const dereference_exprt &deref_expr, + expressionst &out_expressions, + bool &out_is_const) +{ + // We had a pointer, we need to check both the pointer + // type can't be changed, and what it what pointing to + // can't be changed + expressionst pointer_values; + bool pointer_const; + bool resolved= + try_resolve_expression(deref_expr.pointer(), pointer_values, pointer_const); + if(resolved && pointer_const) + { + bool all_objects_const=true; + for(const exprt &pointer_val : pointer_values) + { + if(pointer_val.id()==ID_address_of) + { + address_of_exprt address_expr=to_address_of_expr(pointer_val); + bool object_const=false; + expressionst out_object_values; + bool resolved= + try_resolve_expression( + address_expr.object(), out_object_values, object_const); + + if(resolved) + { + out_expressions.insert( + out_expressions.end(), + out_object_values.begin(), + out_object_values.end()); + + all_objects_const&=object_const; + } + else + { + LOG("Failed to resolve value of a dereference", address_expr); + } + } + else + { + LOG( + "Squashing dereference did not result in an address", pointer_val); + return false; + } + } + out_is_const=all_objects_const; + return true; + } + else + { + if(!resolved) + { + LOG("Failed to resolve pointer of dereference", deref_expr); + } + else if(!pointer_const) + { + LOG("Pointer value not const so can't squash", deref_expr); + } + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::try_resolve_dereference + + Inputs: + typecast_expr - The typecast expression to resolve. + out_expressions - The expressions this typecast could be + out_is_const - Is the squashed expression constant + + Outputs: Returns true if it was able to squash the typecast expression + If this is the case, out_expressions will contain + the possible values after removing the typecast. + + Purpose: To squash a typecast access. + +\*******************************************************************/ + +bool remove_const_function_pointerst::try_resolve_typecast( + const typecast_exprt &typecast_expr, + expressionst &out_expressions, + bool &out_is_const) +{ + expressionst typecast_values; + bool typecast_const; + bool resolved= + try_resolve_expression( + typecast_expr.op(), typecast_values, typecast_const); + + if(resolved) + { + out_expressions.insert( + out_expressions.end(), + typecast_values.begin(), + typecast_values.end()); + out_is_const=typecast_const; + return true; + } + else + { + LOG("Could not resolve typecast value", typecast_expr); + return false; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::is_expression_const + + Inputs: + expression - The expression to check + + Outputs: Returns true if the type of the expression is constant. + + Purpose: To evaluate the const-ness of the expression type. + +\*******************************************************************/ + +bool remove_const_function_pointerst::is_const_expression( + const exprt &expression) const +{ + return is_const_type(expression.type()); +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::is_type_const + + Inputs: + type - The type to check + + Outputs: Returns true if the type has ID_C_constant or is an array + since arrays are implicitly const in C. + + Purpose: To evaluate the const-ness of the type. + +\*******************************************************************/ + +bool remove_const_function_pointerst::is_const_type(const typet &type) const +{ + c_qualifierst qualifers(type); + if(type.id()==ID_array) + { + c_qualifierst array_type_qualifers(type.subtype()); + return qualifers.is_constant || array_type_qualifers.is_constant; + } + else + { + return qualifers.is_constant; + } +} + +/*******************************************************************\ + +Function: remove_const_function_pointerst::get_component_value + + Inputs: + struct_expr - The expression of the structure being accessed + member_expr - The expression saying which component is being accessed + + Outputs: Returns the value of a specific component for a given struct + expression. + + Purpose: To extract the value of the specific component within a struct + +\*******************************************************************/ + +exprt remove_const_function_pointerst::get_component_value( + const struct_exprt &struct_expr, const member_exprt &member_expr) +{ + const struct_typet &struct_type=to_struct_type(ns.follow(struct_expr.type())); + size_t component_number= + struct_type.component_number(member_expr.get_component_name()); + + return struct_expr.operands()[component_number]; +} diff --git a/src/goto-programs/remove_const_function_pointers.h b/src/goto-programs/remove_const_function_pointers.h new file mode 100644 index 00000000000..6516fb6ec64 --- /dev/null +++ b/src/goto-programs/remove_const_function_pointers.h @@ -0,0 +1,105 @@ +/*******************************************************************\ + +Module: Goto Programs + +Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_REMOVE_CONST_FUNCTION_POINTERS_H +#define CPROVER_GOTO_PROGRAMS_REMOVE_CONST_FUNCTION_POINTERS_H + +#include + +#include "goto_model.h" +#include +#include +#include + + +class remove_const_function_pointerst:public messaget +{ +public: + typedef std::unordered_set functionst; + typedef std::list expressionst; + remove_const_function_pointerst( + message_handlert &message_handler, + const exprt &base_expression, + const namespacet &ns, + const symbol_tablet &symbol_table); + + bool operator()(functionst &out_functions); + +private: + exprt replace_const_symbols(const exprt &expression) const; + exprt resolve_symbol(const symbol_exprt &symbol_expr) const; + + // recursive functions for dealing with the function pointer + bool try_resolve_function_call(const exprt &expr, functionst &out_functions); + + bool try_resolve_function_calls( + const expressionst &exprs, functionst &out_functions); + + bool try_resolve_index_of_function_call( + const index_exprt &index_expr, functionst &out_functions); + + bool try_resolve_member_function_call( + const member_exprt &member_expr, functionst &out_functions); + + bool try_resolve_address_of_function_call( + const address_of_exprt &address_expr, functionst &out_functions); + + bool try_resolve_dereference_function_call( + const dereference_exprt &deref_expr, functionst &out_functions); + + bool try_resolve_typecast_function_call( + const typecast_exprt &typecast_expr, functionst &out_functions); + + // recursive functions for dealing with the auxiliary elements + bool try_resolve_expression( + const exprt &expr, + expressionst &out_resolved_expression, + bool &out_is_const); + + bool try_resolve_index_of( + const index_exprt &index_expr, + expressionst &out_expressions, + bool &out_is_const); + + bool try_resolve_member( + const member_exprt &member_expr, + expressionst &out_expressions, + bool &out_is_const); + + bool try_resolve_dereference( + const dereference_exprt &deref_expr, + expressionst &out_expressions, + bool &out_is_const); + + bool try_resolve_typecast( + const typecast_exprt &typecast_expr, + expressionst &out_expressions, + bool &out_is_const); + + bool is_const_expression(const exprt &expression) const; + bool is_const_type(const typet &type) const; + + bool try_resolve_index_value( + const exprt &index_value_expr, mp_integer &out_array_index); + + exprt get_component_value( + const struct_exprt &struct_expr, const member_exprt &member_expr); + + const exprt original_expression; + const namespacet &ns; + const symbol_tablet &symbol_table; +}; + +#define OPT_REMOVE_CONST_FUNCTION_POINTERS \ + "(remove-const-function-pointers)" + +#define HELP_REMOVE_CONST_FUNCTION_POINTERS \ + " --remove-const-function-pointers Remove function pointers that are constant or constant part of an array\n" // NOLINT(*) + + +#endif // CPROVER_GOTO_PROGRAMS_REMOVE_CONST_FUNCTION_POINTERS_H diff --git a/src/goto-programs/remove_function_pointers.cpp b/src/goto-programs/remove_function_pointers.cpp index 3893729a1e1..c67c834b2ce 100644 --- a/src/goto-programs/remove_function_pointers.cpp +++ b/src/goto-programs/remove_function_pointers.cpp @@ -14,12 +14,17 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include +#include +#include +#include #include #include "remove_skip.h" #include "remove_function_pointers.h" #include "compute_called_functions.h" +#include "remove_const_function_pointers.h" /*******************************************************************\ @@ -29,12 +34,14 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ -class remove_function_pointerst +class remove_function_pointerst:public messaget { public: remove_function_pointerst( + message_handlert &_message_handler, symbol_tablet &_symbol_table, bool _add_safety_assertion, + bool only_resolve_const_fps, const goto_functionst &goto_functions); void operator()(goto_functionst &goto_functions); @@ -46,6 +53,14 @@ class remove_function_pointerst symbol_tablet &symbol_table; bool add_safety_assertion; + // We can optionally halt the FP removal if we aren't able to use + // remove_const_function_pointerst to sucessfully narrow to a small + // subset of possible functions and just leave the function pointer + // as it is. + // This can be activated in goto-instrument using + // --remove-const-function-pointers instead of --remove-function-pointers + bool only_resolve_const_fps; + void remove_function_pointer( goto_programt &goto_program, goto_programt::targett target); @@ -92,12 +107,15 @@ Function: remove_function_pointerst::remove_function_pointerst \*******************************************************************/ remove_function_pointerst::remove_function_pointerst( + message_handlert &_message_handler, symbol_tablet &_symbol_table, - bool _add_safety_assertion, + bool _add_safety_assertion, bool only_resolve_const_fps, const goto_functionst &goto_functions): + messaget(_message_handler), ns(_symbol_table), symbol_table(_symbol_table), - add_safety_assertion(_add_safety_assertion) + add_safety_assertion(_add_safety_assertion), + only_resolve_const_fps(only_resolve_const_fps) { compute_address_taken_in_symbols(address_taken); compute_address_taken_functions(goto_functions, address_taken); @@ -338,41 +356,71 @@ void remove_function_pointerst::remove_function_pointer( assert(function.id()==ID_dereference); assert(function.operands().size()==1); - const exprt &pointer=function.op0(); + bool found_functions; - // Is this simple? - if(pointer.id()==ID_address_of && - to_address_of_expr(pointer).object().id()==ID_symbol) + const exprt &pointer=function.op0(); + remove_const_function_pointerst::functionst functions; + does_remove_constt const_removal_check(goto_program, ns); + if(const_removal_check()) { - to_code_function_call(target->code).function()= - to_address_of_expr(pointer).object(); - return; + warning() << "Cast from const to non-const pointer found, only worst case" + << " function pointer removal will be done." << eom; + found_functions=false; } + else + { + remove_const_function_pointerst fpr( + get_message_handler(), pointer, ns, symbol_table); - typedef std::list functionst; - functionst functions; + found_functions=fpr(functions); - bool return_value_used=code.lhs().is_not_nil(); + // Either found_functions is true therefore the functions should not + // be empty + // Or found_functions is false therefore the functions should be empty + assert(found_functions != functions.empty()); - // get all type-compatible functions - // whose address is ever taken - for(const auto &t : type_map) + if(functions.size()==1) + { + to_code_function_call(target->code).function()=*functions.cbegin(); + return; + } + } + + if(!found_functions) { - // address taken? - if(address_taken.find(t.first)==address_taken.end()) - continue; + if(only_resolve_const_fps) + { + // If this mode is enabled, we only remove function pointers + // that we can resolve either to an exact funciton, or an exact subset + // (e.g. a variable index in a constant array). + // Since we haven't found functions, we would now resort to + // replacing the function pointer with any function with a valid signature + // Since we don't want to do that, we abort. + return; + } + + bool return_value_used=code.lhs().is_not_nil(); - // type-compatible? - if(!is_type_compatible(return_value_used, call_type, t.second)) - continue; + // get all type-compatible functions + // whose address is ever taken + for(const auto &t : type_map) + { + // address taken? + if(address_taken.find(t.first)==address_taken.end()) + continue; + + // type-compatible? + if(!is_type_compatible(return_value_used, call_type, t.second)) + continue; - if(t.first=="pthread_mutex_cleanup") - continue; + if(t.first=="pthread_mutex_cleanup") + continue; - symbol_exprt expr; - expr.type()=t.second; - expr.set_identifier(t.first); - functions.push_back(expr); + symbol_exprt expr; + expr.type()=t.second; + expr.set_identifier(t.first); + functions.insert(expr); + } } // the final target is a skip @@ -539,14 +587,20 @@ Function: remove_function_pointers \*******************************************************************/ -bool remove_function_pointers( +bool remove_function_pointers(message_handlert &_message_handler, symbol_tablet &symbol_table, const goto_functionst &goto_functions, goto_programt &goto_program, - bool add_safety_assertion) + bool add_safety_assertion, + bool only_remove_const_fps) { remove_function_pointerst - rfp(symbol_table, add_safety_assertion, goto_functions); + rfp( + _message_handler, + symbol_table, + add_safety_assertion, + only_remove_const_fps, + goto_functions); return rfp.remove_function_pointers(goto_program); } @@ -564,12 +618,19 @@ Function: remove_function_pointers \*******************************************************************/ void remove_function_pointers( + message_handlert &_message_handler, symbol_tablet &symbol_table, goto_functionst &goto_functions, - bool add_safety_assertion) + bool add_safety_assertion, + bool only_remove_const_fps) { remove_function_pointerst - rfp(symbol_table, add_safety_assertion, goto_functions); + rfp( + _message_handler, + symbol_table, + add_safety_assertion, + only_remove_const_fps, + goto_functions); rfp(goto_functions); } @@ -586,11 +647,15 @@ Function: remove_function_pointers \*******************************************************************/ -void remove_function_pointers( +void remove_function_pointers(message_handlert &_message_handler, goto_modelt &goto_model, - bool add_safety_assertion) + bool add_safety_assertion, + bool only_remove_const_fps) { remove_function_pointers( - goto_model.symbol_table, goto_model.goto_functions, - add_safety_assertion); + _message_handler, + goto_model.symbol_table, + goto_model.goto_functions, + add_safety_assertion, + only_remove_const_fps); } diff --git a/src/goto-programs/remove_function_pointers.h b/src/goto-programs/remove_function_pointers.h index 6f1f26984df..e8eea37ea75 100644 --- a/src/goto-programs/remove_function_pointers.h +++ b/src/goto-programs/remove_function_pointers.h @@ -12,22 +12,29 @@ Date: June 2003 #define CPROVER_GOTO_PROGRAMS_REMOVE_FUNCTION_POINTERS_H #include "goto_model.h" +#include // remove indirect function calls // and replace by case-split void remove_function_pointers( + message_handlert &_message_handler, goto_modelt &goto_model, - bool add_safety_assertion); + bool add_safety_assertion, + bool only_remove_const_fps=false); void remove_function_pointers( + message_handlert &_message_handler, symbol_tablet &symbol_table, goto_functionst &goto_functions, - bool add_safety_assertion); + bool add_safety_assertion, + bool only_remove_const_fps=false); bool remove_function_pointers( + message_handlert &_message_handler, symbol_tablet &symbol_table, const goto_functionst &goto_functions, goto_programt &goto_program, - bool add_safety_assertion); + bool add_safety_assertion, + bool only_remove_const_fps=false); #endif // CPROVER_GOTO_PROGRAMS_REMOVE_FUNCTION_POINTERS_H diff --git a/src/musketeer/musketeer_parse_options.cpp b/src/musketeer/musketeer_parse_options.cpp index 707ec50bd0b..de8696d449c 100644 --- a/src/musketeer/musketeer_parse_options.cpp +++ b/src/musketeer/musketeer_parse_options.cpp @@ -215,7 +215,10 @@ void goto_fence_inserter_parse_optionst::instrument_goto_program( if(cmdline.isset("remove-function-pointers")) { status() << "remove soundly function pointers" << eom; - remove_function_pointers(symbol_table, goto_functions, + remove_function_pointers( + get_message_handler(), + symbol_table, + goto_functions, cmdline.isset("pointer-check")); }