Commit b12eb050 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

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.
parent 23e0d718
Pipeline #1872 failed with stages
in 58 minutes and 39 seconds
......@@ -509,7 +509,8 @@ namespace
const spot::const_twa_graph_ptr& aut_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)
<< '*' << autname(j, true)
......
......@@ -649,7 +649,8 @@ static spot::twa_graph_ptr
product(spot::twa_graph_ptr left, spot::twa_graph_ptr right)
{
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);
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)
{
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);
right = ensure_tba(right);
......@@ -965,7 +967,8 @@ parse_opt(int key, char* arg, struct argp_state*)
if (res < 0)
error(2, 0, "acceptance sets should be non-negative:"
" --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"
" acceptance sets: --mask-acc=%ld", res);
opt_mask_acc.set(res);
......
......@@ -691,7 +691,8 @@ namespace
const spot::const_twa_graph_ptr& aut_j,
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
// complemented, or the --verbose option is used,
......
......@@ -151,7 +151,7 @@ namespace spot
bitset& operator<<=(unsigned s)
{
#if SPOT_DEBUG || SWIG
#if SPOT_DEBUG || defined(SWIGPYTHON)
if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
internal::report_bit_shift_too_big();
#else
......@@ -191,7 +191,7 @@ namespace spot
bitset& operator>>=(unsigned s)
{
#if SPOT_DEBUG || SWIG
#if SPOT_DEBUG || defined(SWIGPYTHON)
if (SPOT_UNLIKELY(s >= 8 * N * sizeof(word_t)))
internal::report_bit_shift_too_big();
#else
......
......@@ -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()
{
return mark_t(_value_t::mone());
......@@ -220,7 +230,7 @@ namespace spot
return id ^ r.id;
}
#if SPOT_DEBUG || SWIG
#if SPOT_DEBUG || defined(SWIGPYTHON)
# define SPOT_WRAP_OP(ins) \
try \
{ \
......@@ -567,7 +577,7 @@ namespace spot
if (n == 0)
return inf({});
acc_cond::mark_t m = mark_t::all();
m >>= (SPOT_MAX_ACCSETS - n);
m >>= mark_t::max_accsets() - n;
return inf(m);
}
......@@ -576,7 +586,7 @@ namespace spot
if (n == 0)
return fin({});
acc_cond::mark_t m = mark_t::all();
m >>= (SPOT_MAX_ACCSETS - n);
m >>= mark_t::max_accsets() - n;
return fin(m);
}
......@@ -833,6 +843,8 @@ namespace spot
acc_code& operator<<=(unsigned sets)
{
if (SPOT_UNLIKELY(sets >= mark_t::max_accsets()))
report_too_many_sets();
if (empty())
return *this;
unsigned pos = size();
......@@ -1247,9 +1259,11 @@ namespace spot
if (num == 0)
return -1U;
unsigned j = num_;
num_ += num;
if (num_ > SPOT_MAX_ACCSETS)
num += j;
if (num > mark_t::max_accsets())
report_too_many_sets();
// Make sure we do not update if we raised an exception.
num_ = num;
all_ = all_sets_();
return j;
}
......@@ -1386,7 +1400,7 @@ namespace spot
protected:
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_;
......
......@@ -64,8 +64,10 @@ int main()
auto m1 = spot::acc_cond::mark_t({0, 2});
auto m2 = spot::acc_cond::mark_t({0, 3});
auto m3 = spot::acc_cond::mark_t({2, 1});
auto m4 = spot::acc_cond::mark_t({0, SPOT_MAX_ACCSETS - 2});
if (!(m4.min_set() == 1 && m4.max_set() == SPOT_MAX_ACCSETS - 1))
auto m4 =
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;
spot::acc_cond::mark_t m0 = {};
......@@ -184,33 +186,39 @@ int main()
assert(c1 == c2);
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));
}
{
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_MAX_ACCSETS + 1;
}
{
spot::acc_cond::mark_t m{0};
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));
}
{
assert(!std::strncmp(e.what(), "Too many acceptance sets used.", 30));
}
try
{
spot::acc_cond::mark_t m{0};
m >>= SPOT_MAX_ACCSETS + 1;
}
{
spot::acc_cond::mark_t m{0};
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));
}
{
assert(!std::strncmp(e.what(), "Too many acceptance sets used.", 30));
}
#endif
return 0;
}
......@@ -129,3 +129,13 @@ except RuntimeError as e:
assert "safety" in str(e)
else:
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()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment