fix and check shifting issue

The exception raised by << and >> when shifting mark_t by too many
bits are only enabled in SPOT_DEBUG, as those operations are quite
low-level.  However we were always testing them, and although we
wanted them to be active in Python, it was not always the case.

* spot/twa/acc.hh: introduce max_accsets() as
a static constexpr method, so we can see it in Python.
* spot/misc/bitset.hh: Fix preprocessing directive
so the check is actually enabled when compiling the Python
bindings.
* bin/autcross.cc, bin/autfilt.cc, bin/ltlcross.cc: Use max_accsets().
* tests/core/acc.cc: Comment out the shifting exception when
SPOT_DEBUG is unset.
* tests/python/except.py: Make sure the exception is always raised in
Python.
This commit is contained in:
Alexandre Duret-Lutz 2018-05-25 11:29:59 +02:00
parent 23e0d718fd
commit b12eb0508f
7 changed files with 75 additions and 38 deletions

View file

@ -509,7 +509,8 @@ namespace
const spot::const_twa_graph_ptr& aut_j, const spot::const_twa_graph_ptr& aut_j,
size_t i, size_t j) size_t i, size_t j)
{ {
if (aut_i->num_sets() + aut_j->num_sets() > SPOT_MAX_ACCSETS) if (aut_i->num_sets() + aut_j->num_sets() >
spot::acc_cond::mark_t::max_accsets())
{ {
std::cerr << "info: building " << autname(i) std::cerr << "info: building " << autname(i)
<< '*' << autname(j, true) << '*' << autname(j, true)

View file

@ -649,7 +649,8 @@ static spot::twa_graph_ptr
product(spot::twa_graph_ptr left, spot::twa_graph_ptr right) product(spot::twa_graph_ptr left, spot::twa_graph_ptr right)
{ {
if ((type == spot::postprocessor::BA) if ((type == spot::postprocessor::BA)
&& (left->num_sets() + right->num_sets() > SPOT_MAX_ACCSETS)) && (left->num_sets() + right->num_sets() >
spot::acc_cond::mark_t::max_accsets()))
{ {
left = ensure_tba(left); left = ensure_tba(left);
right = ensure_tba(right); right = ensure_tba(right);
@ -661,7 +662,8 @@ static spot::twa_graph_ptr
product_or(spot::twa_graph_ptr left, spot::twa_graph_ptr right) product_or(spot::twa_graph_ptr left, spot::twa_graph_ptr right)
{ {
if ((type == spot::postprocessor::BA) if ((type == spot::postprocessor::BA)
&& (left->num_sets() + right->num_sets() > SPOT_MAX_ACCSETS)) && (left->num_sets() + right->num_sets() >
spot::acc_cond::mark_t::max_accsets()))
{ {
left = ensure_tba(left); left = ensure_tba(left);
right = ensure_tba(right); right = ensure_tba(right);
@ -965,7 +967,8 @@ parse_opt(int key, char* arg, struct argp_state*)
if (res < 0) if (res < 0)
error(2, 0, "acceptance sets should be non-negative:" error(2, 0, "acceptance sets should be non-negative:"
" --mask-acc=%ld", res); " --mask-acc=%ld", res);
if (static_cast<unsigned long>(res) > SPOT_MAX_ACCSETS) if (static_cast<unsigned long>(res) >=
spot::acc_cond::mark_t::max_accsets())
error(2, 0, "this implementation does not support that many" error(2, 0, "this implementation does not support that many"
" acceptance sets: --mask-acc=%ld", res); " acceptance sets: --mask-acc=%ld", res);
opt_mask_acc.set(res); opt_mask_acc.set(res);

View file

@ -691,7 +691,8 @@ namespace
const spot::const_twa_graph_ptr& aut_j, const spot::const_twa_graph_ptr& aut_j,
size_t i, size_t j, bool icomp, bool jcomp) size_t i, size_t j, bool icomp, bool jcomp)
{ {
if (aut_i->num_sets() + aut_j->num_sets() > SPOT_MAX_ACCSETS) if (aut_i->num_sets() + aut_j->num_sets() >
spot::acc_cond::mark_t::max_accsets())
{ {
// Report the skipped test if both automata are not // Report the skipped test if both automata are not
// complemented, or the --verbose option is used, // complemented, or the --verbose option is used,

View file

@ -151,7 +151,7 @@ namespace spot
bitset& operator<<=(unsigned s) bitset& operator<<=(unsigned s)
{ {
#if SPOT_DEBUG || SWIG #if SPOT_DEBUG || defined(SWIGPYTHON)
if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t))) if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
internal::report_bit_shift_too_big(); internal::report_bit_shift_too_big();
#else #else
@ -191,7 +191,7 @@ namespace spot
bitset& operator>>=(unsigned s) bitset& operator>>=(unsigned s)
{ {
#if SPOT_DEBUG || SWIG #if SPOT_DEBUG || defined(SWIGPYTHON)
if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t))) if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
internal::report_bit_shift_too_big(); internal::report_bit_shift_too_big();
#else #else

View file

@ -94,6 +94,16 @@ namespace spot
} }
} }
/// \brief The maximum number of acceptance sets supported by
/// this implementation.
///
/// The value can be changed at compile-time using configure's
/// --enable-max-accsets=N option.
constexpr static unsigned max_accsets()
{
return SPOT_MAX_ACCSETS;
}
static mark_t all() static mark_t all()
{ {
return mark_t(_value_t::mone()); return mark_t(_value_t::mone());
@ -220,7 +230,7 @@ namespace spot
return id ^ r.id; return id ^ r.id;
} }
#if SPOT_DEBUG || SWIG #if SPOT_DEBUG || defined(SWIGPYTHON)
# define SPOT_WRAP_OP(ins) \ # define SPOT_WRAP_OP(ins) \
try \ try \
{ \ { \
@ -567,7 +577,7 @@ namespace spot
if (n == 0) if (n == 0)
return inf({}); return inf({});
acc_cond::mark_t m = mark_t::all(); acc_cond::mark_t m = mark_t::all();
m >>= (SPOT_MAX_ACCSETS - n); m >>= mark_t::max_accsets() - n;
return inf(m); return inf(m);
} }
@ -576,7 +586,7 @@ namespace spot
if (n == 0) if (n == 0)
return fin({}); return fin({});
acc_cond::mark_t m = mark_t::all(); acc_cond::mark_t m = mark_t::all();
m >>= (SPOT_MAX_ACCSETS - n); m >>= mark_t::max_accsets() - n;
return fin(m); return fin(m);
} }
@ -833,6 +843,8 @@ namespace spot
acc_code& operator<<=(unsigned sets) acc_code& operator<<=(unsigned sets)
{ {
if (SPOT_UNLIKELY(sets >= mark_t::max_accsets()))
report_too_many_sets();
if (empty()) if (empty())
return *this; return *this;
unsigned pos = size(); unsigned pos = size();
@ -1247,9 +1259,11 @@ namespace spot
if (num == 0) if (num == 0)
return -1U; return -1U;
unsigned j = num_; unsigned j = num_;
num_ += num; num += j;
if (num_ > SPOT_MAX_ACCSETS) if (num > mark_t::max_accsets())
report_too_many_sets(); report_too_many_sets();
// Make sure we do not update if we raised an exception.
num_ = num;
all_ = all_sets_(); all_ = all_sets_();
return j; return j;
} }
@ -1386,7 +1400,7 @@ namespace spot
protected: protected:
mark_t all_sets_() const mark_t all_sets_() const
{ {
return mark_t::all() >> (SPOT_MAX_ACCSETS - num_); return mark_t::all() >> (spot::acc_cond::mark_t::max_accsets() - num_);
} }
unsigned num_; unsigned num_;

View file

@ -64,8 +64,10 @@ int main()
auto m1 = spot::acc_cond::mark_t({0, 2}); auto m1 = spot::acc_cond::mark_t({0, 2});
auto m2 = spot::acc_cond::mark_t({0, 3}); auto m2 = spot::acc_cond::mark_t({0, 3});
auto m3 = spot::acc_cond::mark_t({2, 1}); auto m3 = spot::acc_cond::mark_t({2, 1});
auto m4 = spot::acc_cond::mark_t({0, SPOT_MAX_ACCSETS - 2}); auto m4 =
if (!(m4.min_set() == 1 && m4.max_set() == SPOT_MAX_ACCSETS - 1)) spot::acc_cond::mark_t({0, spot::acc_cond::mark_t::max_accsets() - 2});
if (!((m4.min_set() == 1) &&
(m4.max_set() == spot::acc_cond::mark_t::max_accsets() - 1)))
return 1; return 1;
spot::acc_cond::mark_t m0 = {}; spot::acc_cond::mark_t m0 = {};
@ -185,7 +187,22 @@ int main()
try try
{ {
spot::acc_cond a{SPOT_MAX_ACCSETS + 1}; spot::acc_cond a{spot::acc_cond::mark_t::max_accsets() + 1};
}
catch (const std::runtime_error& e)
{
assert(!std::strncmp(e.what(), "Too many acceptance sets used.", 30));
}
#if SPOT_DEBUG
// Those error message are disabled in non-debugging code as
// shifting mark_t is usually done in the innermost loop of
// algorithms. However, they are still done in Python, and we
// test them in python/except.py
try
{
spot::acc_cond::mark_t m{0};
m <<= spot::acc_cond::mark_t::max_accsets() + 1;
} }
catch (const std::runtime_error& e) catch (const std::runtime_error& e)
{ {
@ -195,22 +212,13 @@ int main()
try try
{ {
spot::acc_cond::mark_t m{0}; spot::acc_cond::mark_t m{0};
m <<= SPOT_MAX_ACCSETS + 1; m >>= spot::acc_cond::mark_t::max_accsets() + 1;
}
catch (const std::runtime_error& e)
{
assert(!std::strncmp(e.what(), "Too many acceptance sets used.", 30));
}
try
{
spot::acc_cond::mark_t m{0};
m >>= SPOT_MAX_ACCSETS + 1;
} }
catch (const std::runtime_error& e) catch (const std::runtime_error& e)
{ {
assert(!std::strncmp(e.what(), "Too many acceptance sets used.", 30)); assert(!std::strncmp(e.what(), "Too many acceptance sets used.", 30));
} }
#endif
return 0; return 0;
} }

View file

@ -129,3 +129,13 @@ except RuntimeError as e:
assert "safety" in str(e) assert "safety" in str(e)
else: else:
report_missing_exception() report_missing_exception()
n = spot.mark_t.max_accsets()
m = spot.mark_t([n - 1])
try:
m = spot.mark_t([0]) << n
except RuntimeError as e:
assert "Too many acceptance sets" in str(e)
else:
print(n, m)
report_missing_exception()