never iterate on the edge_vector()

This fixes #552, reported by Rüdiger and Ayrat.

* tests/sanity/style.test: Warn aginst iterations on edge_vector.
* spot/parseaut/parseaut.yy, spot/twaalgos/complete.cc,
spot/twaalgos/parity.cc: Iterate over edges(), not edge_vector().
* tests/core/ltlcross.test: Add a test case for #552.
* NEWS: Mention the bug.
This commit is contained in:
Alexandre Duret-Lutz 2023-11-17 22:07:40 +01:00
parent 313e43c84b
commit 205df01390
6 changed files with 27 additions and 7 deletions

10
NEWS
View file

@ -156,6 +156,16 @@ New in spot 2.11.6.dev (not yet released)
could fail to equate two "t" condition, because we have two ways could fail to equate two "t" condition, because we have two ways
to represent "t": the empty condition, or the empty "Inf({})". to represent "t": the empty condition, or the empty "Inf({})".
- Functions complement() and change_parity() could incorrectly read
or write the unused edge #0. In the case of complement(), writing
that edge was usually harmless. However in some scenario,
complement could need to stick a ⓪ acceptance mark on edge #0,
then the acceptance condition could be simplified to "t", and
finally change_parity could be confused to find such an accepting
mark in an automaton that declares no colors, and perform some
computation on that color that caused it to crash with a "Too many
acceptance sets used" message. (issue #552)
New in spot 2.11.6 (2023-08-01) New in spot 2.11.6 (2023-08-01)
Bug fixes: Bug fixes:

View file

@ -2556,7 +2556,7 @@ static void fix_acceptance(result_& r)
auto onlyneg = r.neg_acc_sets - r.pos_acc_sets; auto onlyneg = r.neg_acc_sets - r.pos_acc_sets;
if (onlyneg) if (onlyneg)
{ {
for (auto& t: r.h->aut->edge_vector()) for (auto& t: r.h->aut->edges())
t.acc ^= onlyneg; t.acc ^= onlyneg;
} }
@ -2570,7 +2570,7 @@ static void fix_acceptance(result_& r)
if (both) if (both)
{ {
base = acc.add_sets(both.count()); base = acc.add_sets(both.count());
for (auto& t: r.h->aut->edge_vector()) for (auto& t: r.h->aut->edges())
{ {
unsigned i = 0; unsigned i = 0;
if ((t.acc & both) != both) if ((t.acc & both) != both)

View file

@ -144,7 +144,7 @@ namespace spot
if (need_acc_fix) if (need_acc_fix)
{ {
auto a = aut->set_buchi(); auto a = aut->set_buchi();
for (auto& t: aut->edge_vector()) for (auto& t: aut->edges())
t.acc = a; t.acc = a;
if (aut->num_edges()) if (aut->num_edges())
acc = a; acc = a;

View file

@ -50,7 +50,7 @@ namespace spot
change_acc(twa_graph_ptr& aut, unsigned num_sets, bool change_kind, change_acc(twa_graph_ptr& aut, unsigned num_sets, bool change_kind,
bool change_style, bool output_max, bool input_max) bool change_style, bool output_max, bool input_max)
{ {
for (auto& e: aut->edge_vector()) for (auto& e: aut->edges())
if (e.acc) if (e.acc)
{ {
unsigned msb = (input_max ? e.acc.max_set() : e.acc.min_set()) - 1; unsigned msb = (input_max ? e.acc.max_set() : e.acc.min_set()) - 1;

View file

@ -69,7 +69,12 @@ ltlcross --verbose ltl2tgba ltl2tgba \
# Issue #524. # Issue #524.
ltlcross ltl2tgba -f '!(X(v3 | G!v5) | ((Xv5 & !(v5 & !X!v3)) U !v5))' ltlcross ltl2tgba -f '!(X(v3 | G!v5) | ((Xv5 & !(v5 & !X!v3)) U !v5))'
# Issue #546. # Issue #546, Issue #552.
ltlcross 'ltl2tgba --medium -p' 'ltl2tgba -p' 'ltl2tgba --medium -D -p' \ ltlcross 'ltl2tgba --medium -p' \
'ltl2tgba -p' \
'ltl2tgba --medium -D -p' \
'ltl2tgba --medium --colored-parity="min even" -C -D' \
'ltl2tgba --colored-parity="min even" -C -D' \
-f 'a | FGa | GF(!b | Gb)' \ -f 'a | FGa | GF(!b | Gb)' \
-f '(~ v1 U ~ v5) | G(F v9 & F G v1) | G F(~ v7 | G v7 | G v3)' -f '(~ v1 U ~ v5) | G(F v9 & F G v1) | G F(~ v7 | G v7 | G v3)' \
-f 'FG((a | Fb | FG!b) & !G(c & d))'

View file

@ -298,6 +298,11 @@ for dir in "$TOP/spot" "$TOP/bin" "$TOP/tests"; do
$GREP 'catch *([^.]' $tmp | $GREP -v 'const.*&' && $GREP 'catch *([^.]' $tmp | $GREP -v 'const.*&' &&
diag 'Always capture exceptions by const reference.' diag 'Always capture exceptions by const reference.'
# iterating over edge_vector() is suspicious, because the
# first edge should not be used.
$GREP 'for (.*:.*edge_vector()' $tmp &&
diag 'Did you mean to iterate over edges()?'
case $file in case $file in
*.hh | *.hxx) *.hh | *.hxx)
if $GREP -E '(<<|>>)' $tmp >/dev/null; then if $GREP -E '(<<|>>)' $tmp >/dev/null; then