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

Reply via email to