Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fuzz] Fix crash with missing choices in aggregate. #1104

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,65 @@ bool eval_possible(tree_t t, unit_registry_t *ur)
return false;
}

// Check for missing choices in constrained array aggregates
type_t composite_type = tree_type(t);
if (type_is_array(composite_type)
&& !type_is_unconstrained(composite_type)) {
int64_t count = 0, elem_count = 0;
bool known_elem_count = false;
bool has_others = false;
bool has_range = false;
for (int i = 0; i < nassocs; i++) {
tree_t a = tree_assoc(t, i);
const assoc_kind_t akind = tree_subkind(a);

switch (akind) {

case A_NAMED:
case A_POS:
known_elem_count = true;
elem_count = 1;
break;

case A_RANGE:
known_elem_count = false;
has_range = true;
break;

case A_OTHERS:
known_elem_count = false;
has_others = true;
break;

case A_SLICE:
case A_CONCAT:
{
type_t v_type = tree_type(tree_value(a));
known_elem_count = true;
if (type_is_unconstrained(v_type))
known_elem_count = false;
else if (!folded_length(range_of(v_type, 0), &elem_count))
known_elem_count = false;
break;
}
}

if (known_elem_count)
count += elem_count;
}

if (has_range)
// Range could overlap, defer to bounds check
return eval_not_possible(t, "range as choice");

if (!has_others) {
int64_t type_count;
if (folded_length(range_of(composite_type, 0), &type_count))
if (count != type_count)
return eval_not_possible(t, "missing choice");
}
}

return true;
}

Expand Down
17 changes: 17 additions & 0 deletions test/bounds/issue1091.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package pkg is
type vec is array(0 to 3) of integer;
end pkg;

use work.pkg.all;

entity ent is
port (
p0 : boolean := vec'(0=>0, 1=>0) = vec'(3=>0);
p1 : boolean := vec'(0=>0, 1=>1, 1 to 2=>1) = vec'(others=>0);
p2 : boolean := vec'(0=>0, 1=>1, 2 to 3=>1) = vec'(others=>0)
);
end ent;

architecture arch of ent is
begin
end architecture arch;
22 changes: 22 additions & 0 deletions test/test_bounds.c
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,27 @@ START_TEST(test_issue1021)
}
END_TEST

START_TEST(test_issue1091)
{
input_from_file(TESTDIR "/bounds/issue1091.vhd");

const error_t expect[] = {
{ 9, "missing choices for elements 2 to 3 of VEC" },
{ 9, "missing choices for elements 0 to 2 of VEC" },
{ 10, "value 1 is already covered" },
{ 10, "missing choice for element 3 of VEC" },
{ -1, NULL }
};
expect_errors(expect);

parse_check_and_simplify(T_PACKAGE, T_ENTITY, T_ARCH);

fail_unless(parse() == NULL);

check_expected_errors();
}
END_TEST

Suite *get_bounds_tests(void)
{
Suite *s = suite_create("bounds");
Expand Down Expand Up @@ -905,6 +926,7 @@ Suite *get_bounds_tests(void)
tcase_add_test(tc_core, test_issue975);
tcase_add_test(tc_core, test_issue1040);
tcase_add_test(tc_core, test_issue1021);
tcase_add_test(tc_core, test_issue1091);
suite_add_tcase(s, tc_core);

return s;
Expand Down
Loading