Skip to content

Commit 79171e0

Browse files
committed
C front-end: reject invalid array declarators
- Reject VLA declarators with * outside function definitions - Reject type qualifiers and storage class specifiers in array declarators outside function prototypes According to the C standard (C99/C11): - Variable length array declarators with * are only valid in function parameter declarations within function definitions (not declarations) - Type qualifiers (like restrict, const, volatile) in array declarators are only valid in function parameter declarations - Storage class specifiers (like static) in array declarators are only valid in function parameter declarations within function prototypes or definitions These constructs are not valid in: - File scope variable declarations - Block scope variable declarations - Any array declarator in non-parameter contexts Fixes: #132
1 parent 4fe3ade commit 79171e0

File tree

8 files changed

+120
-7
lines changed

8 files changed

+120
-7
lines changed

regression/ansi-c/Array_Declarator2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=6$

regression/ansi-c/Array_Declarator3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=6$

regression/ansi-c/Array_Declarator4/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=6$

regression/ansi-c/Array_Declarator5/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=6$

regression/ansi-c/Array_Declarator6/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=6$

regression/ansi-c/Array_Declarator7/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=64$

src/ansi-c/c_typecheck_base.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,25 @@ void c_typecheck_baset::typecheck_function_body(symbolt &symbol)
618618

619619
code_typet &code_type = to_code_type(symbol.type);
620620

621+
// Check for VLA unspecified ([*]) in function definitions
622+
// This is only allowed in function prototypes, not definitions
623+
for(const auto &param : code_type.parameters())
624+
{
625+
typet t = param.type();
626+
while(t.id() == ID_array)
627+
{
628+
const array_typet &array_type = to_array_type(t);
629+
if(array_type.get_bool(ID_C_vla_unspecified))
630+
{
631+
error().source_location = param.source_location();
632+
error() << "'[*]' not allowed in other than function prototype scope"
633+
<< eom;
634+
throw 0;
635+
}
636+
t = array_type.element_type();
637+
}
638+
}
639+
621640
// reset labels
622641
labels_used.clear();
623642
labels_defined.clear();

src/ansi-c/parser.y

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3532,7 +3532,73 @@ cprover_function_contract_sequence_opt:
35323532
;
35333533

35343534
postfixing_abstract_declarator:
3535-
parameter_postfixing_abstract_declarator
3535+
non_parameter_array_abstract_declarator
3536+
| '(' ')'
3537+
{
3538+
// Set function name (last declarator) in source location
3539+
// before parsing function contracts. Only do this if we
3540+
// are at a global scope.
3541+
if (PARSER.current_scope().prefix.empty()) {
3542+
PARSER.set_function(PARSER.current_scope().last_declarator);
3543+
}
3544+
// Use last declarator (i.e., function name) to name
3545+
// the scope.
3546+
PARSER.new_scope(
3547+
id2string(PARSER.current_scope().last_declarator)+"::");
3548+
}
3549+
cprover_function_contract_sequence_opt
3550+
{
3551+
set($1, ID_code);
3552+
stack_type($1).add(ID_parameters);
3553+
stack_type($1).add_subtype()=typet(ID_abstract);
3554+
PARSER.pop_scope();
3555+
3556+
// Clear function name in source location after parsing if
3557+
// at global scope.
3558+
if (PARSER.current_scope().prefix.empty()) {
3559+
PARSER.set_function(irep_idt());
3560+
}
3561+
3562+
$$ = merge($4, $1);
3563+
}
3564+
| '('
3565+
{
3566+
// Set function name (last declarator) in source location
3567+
// before parsing function contracts. Only do this if we
3568+
// are at a global scope.
3569+
if (PARSER.current_scope().prefix.empty()) {
3570+
PARSER.set_function(PARSER.current_scope().last_declarator);
3571+
}
3572+
// Use last declarator (i.e., function name) to name
3573+
// the scope.
3574+
PARSER.new_scope(
3575+
id2string(PARSER.current_scope().last_declarator)+"::");
3576+
}
3577+
parameter_type_list
3578+
')'
3579+
KnR_parameter_header_opt
3580+
cprover_function_contract_sequence_opt
3581+
{
3582+
set($1, ID_code);
3583+
stack_type($1).add_subtype()=typet(ID_abstract);
3584+
stack_type($1).add(ID_parameters).get_sub().
3585+
swap((irept::subt &)(to_type_with_subtypes(stack_type($3)).subtypes()));
3586+
PARSER.pop_scope();
3587+
3588+
// Clear function name in source location after parsing if
3589+
// at global scope.
3590+
if (PARSER.current_scope().prefix.empty()) {
3591+
PARSER.set_function(irep_idt());
3592+
}
3593+
3594+
if(parser_stack($5).is_not_nil())
3595+
{
3596+
adjust_KnR_parameters(parser_stack($$).add(ID_parameters), parser_stack($5));
3597+
parser_stack($$).set(ID_C_KnR, true);
3598+
}
3599+
3600+
$$ = merge($6, $1);
3601+
}
35363602
/* The following two rules implement K&R headers! */
35373603
| '('
35383604
')'
@@ -3636,6 +3702,32 @@ parameter_postfixing_abstract_declarator:
36363702
}
36373703
;
36383704

3705+
non_parameter_array_abstract_declarator:
3706+
'[' ']'
3707+
{
3708+
$$=$1;
3709+
set($$, ID_array);
3710+
stack_type($$).add_subtype()=typet(ID_abstract);
3711+
stack_type($$).add(ID_size).make_nil();
3712+
}
3713+
| '[' constant_expression ']'
3714+
{
3715+
$$=$1;
3716+
set($$, ID_array);
3717+
stack_type($$).add(ID_size).swap(parser_stack($2));
3718+
stack_type($$).add_subtype()=typet(ID_abstract);
3719+
}
3720+
| non_parameter_array_abstract_declarator '[' constant_expression ']'
3721+
{
3722+
// we need to push this down
3723+
$$=$1;
3724+
set($2, ID_array);
3725+
stack_type($2).add(ID_size).swap(parser_stack($3));
3726+
stack_type($2).add_subtype()=typet(ID_abstract);
3727+
make_subtype($1, $2);
3728+
}
3729+
;
3730+
36393731
array_abstract_declarator:
36403732
'[' ']'
36413733
{
@@ -3661,6 +3753,7 @@ array_abstract_declarator:
36613753
set($$, ID_array);
36623754
stack_type($$).add_subtype()=typet(ID_abstract);
36633755
stack_type($$).add(ID_size).make_nil();
3756+
stack_type($$).set(ID_C_vla_unspecified, true);
36643757
}
36653758
| '[' constant_expression ']'
36663759
{
@@ -3695,6 +3788,7 @@ array_abstract_declarator:
36953788
set($2, ID_array);
36963789
stack_type($2).add(ID_size).make_nil();
36973790
stack_type($2).add_subtype()=typet(ID_abstract);
3791+
stack_type($2).set(ID_C_vla_unspecified, true);
36983792
make_subtype($1, $2);
36993793
}
37003794
;

0 commit comments

Comments
 (0)