On 25/03/21 14:48 +0000, Jonathan Wakely wrote:
On 25/03/21 13:05 +0000, Jonathan Wakely wrote:
On 24/03/21 22:48 +0100, François Dumont wrote:
I still need to find out why, when running test on
__gnu_debug::basic_string after the std::basic_string one, the
generate(sz) call always returns sz.
The "random" generator will always return the same sequence of numbers
every time you run the test. It uses a default-constructed
std::mt19937 without a seed, so the sequence of random numbers is 100%
reproducable.
This patch allows those random engines to be seeded, so that we can test
with different random numbers.
It's already found a bug:
GLIBCXX_SEED_TEST_RNG=-941908610 make check
RUNTESTFLAGS=conformance.exp=23_containers/forward_list/requirements/exception/generation_prohibited.cc
Using random seed 3353058686
FAIL:
23_containers/forward_list/requirements/exception/generation_prohibited.cc
execution test
We need to investigate that.
Oh, it's the same generate(sz) bug as you already found. But I've
found other bugs, e.g. with GLIBCXX_SEED_TEST_RNG=1908970375).
I think we should also add a check for non-empty containers to those
test functions, and ensure we don't try to erase from empty
containers (see attached).
diff --git a/libstdc++-v3/testsuite/util/exception/safety.h b/libstdc++-v3/testsuite/util/exception/safety.h
index 16a784e4908..2e5d8acae00 100644
--- a/libstdc++-v3/testsuite/util/exception/safety.h
+++ b/libstdc++-v3/testsuite/util/exception/safety.h
@@ -43,12 +43,12 @@ namespace __gnu_test
{
// A single seed value is much smaller than the mt19937 state size,
// but we're not trying to be cryptographically secure here.
- unsigned s = std::atoi(v);
+ int s = std::atoi(v);
if (s == 0)
- s = std::random_device{}();
- std::printf("Using random seed %u\n", s);
+ s = (int)std::random_device{}();
+ std::printf("Using random seed %d\n", s);
std::fflush(stdout);
- engine.seed(s);
+ engine.seed((unsigned)s);
}
return engine;
}
@@ -318,10 +318,13 @@ namespace __gnu_test
// computed with begin() and end().
const size_type sz = std::distance(__container.begin(),
__container.end());
+ // Container::erase(pos) requires dereferenceable pos.
+ if (sz == 0)
+ throw std::logic_error("erase_point: empty container");
// NB: Lowest common denominator: use forward iterator operations.
auto i = __container.begin();
- std::advance(i, generate(sz));
+ std::advance(i, generate(sz - 1));
// Makes it easier to think of this as __container.erase(i)
(__container.*_F_erase_point)(i);
@@ -346,12 +349,15 @@ namespace __gnu_test
// computed with begin() and end().
const size_type sz = std::distance(__container.begin(),
__container.end());
+ // forward_list::erase_after(pos) requires dereferenceable pos.
+ if (sz == 0)
+ throw std::logic_error("erase_point: empty container");
// NB: Lowest common denominator: use forward iterator operations.
auto i = __container.before_begin();
- std::advance(i, generate(sz));
+ std::advance(i, generate(sz - 1));
- // Makes it easier to think of this as __container.erase(i)
+ // Makes it easier to think of this as __container.erase_after(i)
(__container.*_F_erase_point)(i);
}
catch(const __gnu_cxx::forced_error&)
@@ -414,14 +420,19 @@ namespace __gnu_test
{
const size_type sz = std::distance(__container.begin(),
__container.end());
- size_type s1 = generate(sz);
- size_type s2 = generate(sz);
+ // forward_list::erase_after(pos, last) requires a pos != last
+ if (sz == 0)
+ return; // Caller doesn't check for this, not a logic error.
+
+ size_type s1 = generate(sz - 1);
+ size_type s2 = generate(sz - 1);
auto i1 = __container.before_begin();
auto i2 = __container.before_begin();
std::advance(i1, std::min(s1, s2));
- std::advance(i2, std::max(s1, s2));
+ std::advance(i2, std::max(s1, s2) + 1);
- // Makes it easier to think of this as __container.erase(i1, i2).
+ // Makes it easier to think of this as
+ // __container.erase_after(i1, i2).
(__container.*_F_erase_range)(i1, i2);
}
catch(const __gnu_cxx::forced_error&)
@@ -1463,16 +1474,25 @@ namespace __gnu_test
// constructor or assignment operator of value_type throws.
if (!traits<container_type>::has_throwing_erase::value)
{
- typename base_type::erase_point erasep;
- erasep(container);
+ if (!container.empty())
+ {
+ typename base_type::erase_point erasep;
+ erasep(container);
+ }
typename base_type::erase_range eraser;
eraser(container);
}
- typename base_type::pop_front popf;
- popf(container);
- typename base_type::pop_back popb;
- popb(container);
+ if (!container.empty())
+ {
+ typename base_type::pop_front popf;
+ popf(container);
+ }
+ if (!container.empty())
+ {
+ typename base_type::pop_back popb;
+ popb(container);
+ }
typename base_type::iterator_ops iops;
iops(container);
diff --git a/libstdc++-v3/testsuite/util/testsuite_containergen.h b/libstdc++-v3/testsuite/util/testsuite_containergen.h
index 5bbe620d59d..c468c7f4415 100644
--- a/libstdc++-v3/testsuite/util/testsuite_containergen.h
+++ b/libstdc++-v3/testsuite/util/testsuite_containergen.h
@@ -69,12 +69,12 @@ namespace __gnu_test
{
// A single seed value is much smaller than the mt19937 state size,
// but we're not trying to be cryptographically secure here.
- unsigned s = std::atoi(v);
+ int s = std::atoi(v);
if (s == 0)
- s = std::random_device{}();
- std::printf("Using random seed %u\n", s);
+ s = (int)std::random_device{}();
+ std::printf("Using random seed %d\n", s);
std::fflush(stdout);
- random_gen.seed(s);
+ random_gen.seed((unsigned)s);
}
#ifdef SIMULATOR_TEST