Quellcode durchsuchen

Merge branch 'tor-github/pr/1022'

David Goulet vor 5 Jahren
Ursprung
Commit
29955f13e5

+ 1 - 1
.travis.yml

@@ -42,7 +42,7 @@ matrix:
   ## include creates builds with gcc, linux
   ## include creates builds with gcc, linux
   include:
   include:
     ## We include a single coverage build with the best options for coverage
     ## We include a single coverage build with the best options for coverage
-    - env: COVERAGE_OPTIONS="--enable-coverage" HARDENING_OPTIONS=""
+    - env: COVERAGE_OPTIONS="--enable-coverage" HARDENING_OPTIONS="" TOR_TEST_RNG_SEED="636f766572616765"
     ## We only want to check these build option combinations once
     ## We only want to check these build option combinations once
     ## (they shouldn't vary by compiler or OS)
     ## (they shouldn't vary by compiler or OS)
     ## We run rust and coverage with hardening off, which seems like enough
     ## We run rust and coverage with hardening off, which seems like enough

+ 11 - 0
changes/ticket28878

@@ -0,0 +1,11 @@
+  o Minor features (testing):
+    - The circuitpadding tests now use a reproducible RNG implementation,
+      so that if a test fails, we can learn why. Part of ticket 28878.
+    - Tor's tests now support an environment variable, TOR_TEST_RNG_SEED,
+      to set the RNG seed for tests that use a reproducible RNG.
+      Part of ticket 28878.
+
+  o Minor features (continuous integration):
+    - When running coverage builds on Travis, we now set TOR_TEST_RNG_SEED,
+      to avoid RNG-based coverage differences.
+      Part of ticket 28878.

+ 6 - 0
src/ext/tinytest.c

@@ -492,6 +492,12 @@ tinytest_set_test_skipped_(void)
 		cur_test_outcome = SKIP;
 		cur_test_outcome = SKIP;
 }
 }
 
 
+int
+tinytest_cur_test_has_failed(void)
+{
+	return (cur_test_outcome == FAIL);
+}
+
 char *
 char *
 tinytest_format_hex_(const void *val_, unsigned long len)
 tinytest_format_hex_(const void *val_, unsigned long len)
 {
 {

+ 3 - 0
src/ext/tinytest.h

@@ -72,6 +72,9 @@ struct testlist_alias_t {
 };
 };
 #define END_OF_ALIASES { NULL, NULL }
 #define END_OF_ALIASES { NULL, NULL }
 
 
+/** Return true iff the current test has failed. */
+int tinytest_cur_test_has_failed(void);
+
 /** Implementation: called from a test to indicate failure, before logging. */
 /** Implementation: called from a test to indicate failure, before logging. */
 void tinytest_set_test_failed_(void);
 void tinytest_set_test_failed_(void);
 /** Implementation: called from a test to indicate that we're skipping. */
 /** Implementation: called from a test to indicate that we're skipping. */

+ 32 - 4
src/test/rng_test_helpers.c

@@ -17,6 +17,7 @@
 #include "core/or/or.h"
 #include "core/or/or.h"
 
 
 #include "lib/crypt_ops/crypto_rand.h"
 #include "lib/crypt_ops/crypto_rand.h"
+#include "ext/tinytest.h"
 
 
 #include "test/rng_test_helpers.h"
 #include "test/rng_test_helpers.h"
 
 
@@ -54,7 +55,8 @@ static uint8_t rng_seed[16];
 static crypto_xof_t *rng_xof = NULL;
 static crypto_xof_t *rng_xof = NULL;
 
 
 /**
 /**
- * Print the seed for our PRNG to stdout.  We use this when we're
+ * Print the seed for our PRNG to stdout.  We use this when we're failed
+ * test that had a reproducible RNG set.
  **/
  **/
 void
 void
 testing_dump_reproducible_rng_seed(void)
 testing_dump_reproducible_rng_seed(void)
@@ -122,9 +124,22 @@ enable_deterministic_rng_impl(const uint8_t *seed, size_t seed_len)
 void
 void
 testing_enable_reproducible_rng(void)
 testing_enable_reproducible_rng(void)
 {
 {
-  uint8_t seed[16];
-  crypto_rand((char*)seed, sizeof(seed));
-  enable_deterministic_rng_impl(seed, sizeof(seed));
+  const char *provided_seed = getenv("TOR_TEST_RNG_SEED");
+  if (provided_seed) {
+    size_t hexlen = strlen(provided_seed);
+    size_t seedlen = hexlen / 2;
+    uint8_t *seed = tor_malloc(hexlen / 2);
+    if (base16_decode((char*)seed, seedlen, provided_seed, hexlen) < 0) {
+      puts("Cannot decode value in TOR_TEST_RNG_SEED");
+      exit(1);
+    }
+    enable_deterministic_rng_impl(seed, seedlen);
+    tor_free(seed);
+  } else {
+    uint8_t seed[16];
+    crypto_rand((char*)seed, sizeof(seed));
+    enable_deterministic_rng_impl(seed, sizeof(seed));
+  }
 }
 }
 
 
 /**
 /**
@@ -228,3 +243,16 @@ testing_disable_rng_override(void)
 
 
   rng_is_replaced = false;
   rng_is_replaced = false;
 }
 }
+
+/**
+ * As testing_disable_rng_override(), but dump the seed if the current
+ * test has failed.
+ */
+void
+testing_disable_reproducible_rng(void)
+{
+  if (tinytest_cur_test_has_failed()) {
+    testing_dump_reproducible_rng_seed();
+  }
+  testing_disable_rng_override();
+}

+ 1 - 2
src/test/rng_test_helpers.h

@@ -14,8 +14,7 @@ void testing_prefilled_rng_reset(void);
 
 
 void testing_disable_rng_override(void);
 void testing_disable_rng_override(void);
 
 
-#define testing_disable_reproducible_rng() \
-  testing_disable_rng_override()
+void testing_disable_reproducible_rng(void);
 #define testing_disable_deterministic_rng() \
 #define testing_disable_deterministic_rng() \
   testing_disable_rng_override()
   testing_disable_rng_override()
 #define testing_disable_prefilled_rng() \
 #define testing_disable_prefilled_rng() \

+ 29 - 0
src/test/test_circuitpadding.c

@@ -36,6 +36,8 @@
 #include "core/or/or_circuit_st.h"
 #include "core/or/or_circuit_st.h"
 #include "core/or/origin_circuit_st.h"
 #include "core/or/origin_circuit_st.h"
 
 
+#include "test/rng_test_helpers.h"
+
 /* Start our monotime mocking at 1 second past whatever monotime_init()
 /* Start our monotime mocking at 1 second past whatever monotime_init()
  * thought the actual wall clock time was, for platforms with bad resolution
  * thought the actual wall clock time was, for platforms with bad resolution
  * and weird timevalues during monotime_init() before mocking. */
  * and weird timevalues during monotime_init() before mocking. */
@@ -313,6 +315,7 @@ test_circuitpadding_rtt(void *arg)
 
 
   MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
   MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
   MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
   MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
+  testing_enable_reproducible_rng();
 
 
   dummy_channel.cmux = circuitmux_alloc();
   dummy_channel.cmux = circuitmux_alloc();
   relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
   relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
@@ -416,6 +419,7 @@ test_circuitpadding_rtt(void *arg)
   UNMOCK(circuit_package_relay_cell);
   UNMOCK(circuit_package_relay_cell);
   UNMOCK(circuitmux_attach_circuit);
   UNMOCK(circuitmux_attach_circuit);
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 
 
   return;
   return;
 }
 }
@@ -540,6 +544,7 @@ test_circuitpadding_token_removal_higher(void *arg)
   /* Mock it up */
   /* Mock it up */
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Setup test environment (time etc.) */
   /* Setup test environment (time etc.) */
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
@@ -633,6 +638,7 @@ test_circuitpadding_token_removal_higher(void *arg)
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   monotime_disable_test_mocking();
   monotime_disable_test_mocking();
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /** Test lower token removal strategy by bin  */
 /** Test lower token removal strategy by bin  */
@@ -645,6 +651,7 @@ test_circuitpadding_token_removal_lower(void *arg)
   /* Mock it up */
   /* Mock it up */
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Setup test environment (time etc.) */
   /* Setup test environment (time etc.) */
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
@@ -731,6 +738,7 @@ test_circuitpadding_token_removal_lower(void *arg)
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   monotime_disable_test_mocking();
   monotime_disable_test_mocking();
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /** Test closest token removal strategy by bin  */
 /** Test closest token removal strategy by bin  */
@@ -743,6 +751,7 @@ test_circuitpadding_closest_token_removal(void *arg)
   /* Mock it up */
   /* Mock it up */
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Setup test environment (time etc.) */
   /* Setup test environment (time etc.) */
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
@@ -837,6 +846,7 @@ test_circuitpadding_closest_token_removal(void *arg)
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   monotime_disable_test_mocking();
   monotime_disable_test_mocking();
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /** Test closest token removal strategy with usec  */
 /** Test closest token removal strategy with usec  */
@@ -849,6 +859,7 @@ test_circuitpadding_closest_token_removal_usec(void *arg)
   /* Mock it up */
   /* Mock it up */
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Setup test environment (time etc.) */
   /* Setup test environment (time etc.) */
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
@@ -948,6 +959,7 @@ test_circuitpadding_closest_token_removal_usec(void *arg)
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   monotime_disable_test_mocking();
   monotime_disable_test_mocking();
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /** Test closest token removal strategy with usec  */
 /** Test closest token removal strategy with usec  */
@@ -960,6 +972,7 @@ test_circuitpadding_token_removal_exact(void *arg)
   /* Mock it up */
   /* Mock it up */
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Setup test environment (time etc.) */
   /* Setup test environment (time etc.) */
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
@@ -1007,6 +1020,7 @@ test_circuitpadding_token_removal_exact(void *arg)
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   monotime_disable_test_mocking();
   monotime_disable_test_mocking();
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 #undef BIG_HISTOGRAM_LEN
 #undef BIG_HISTOGRAM_LEN
@@ -1019,6 +1033,8 @@ test_circuitpadding_tokens(void *arg)
   int64_t actual_mocked_monotime_start;
   int64_t actual_mocked_monotime_start;
   (void)arg;
   (void)arg;
 
 
+  testing_enable_reproducible_rng();
+
   /** Test plan:
   /** Test plan:
    *
    *
    * 1. Test symmetry between bin_to_usec and usec_to_bin
    * 1. Test symmetry between bin_to_usec and usec_to_bin
@@ -1272,6 +1288,7 @@ test_circuitpadding_tokens(void *arg)
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   monotime_disable_test_mocking();
   monotime_disable_test_mocking();
   tor_free(circ_client_machine.states);
   tor_free(circ_client_machine.states);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 void
 void
@@ -1299,6 +1316,7 @@ test_circuitpadding_wronghop(void *arg)
   /* Mock this function so that our cell counting tests don't get confused by
   /* Mock this function so that our cell counting tests don't get confused by
    * padding that gets sent by scheduled timers. */
    * padding that gets sent by scheduled timers. */
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
   MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
   dummy_channel.cmux = circuitmux_alloc();
   dummy_channel.cmux = circuitmux_alloc();
@@ -1472,6 +1490,7 @@ test_circuitpadding_wronghop(void *arg)
   UNMOCK(circuit_package_relay_cell);
   UNMOCK(circuit_package_relay_cell);
   UNMOCK(circuitmux_attach_circuit);
   UNMOCK(circuitmux_attach_circuit);
   nodes_free();
   nodes_free();
+  testing_disable_reproducible_rng();
 }
 }
 
 
 void
 void
@@ -1952,6 +1971,7 @@ test_circuitpadding_conditions(void *arg)
   int64_t actual_mocked_monotime_start;
   int64_t actual_mocked_monotime_start;
   (void)arg;
   (void)arg;
   MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
   MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+  testing_enable_reproducible_rng();
 
 
   nodes_init();
   nodes_init();
   dummy_channel.cmux = circuitmux_alloc();
   dummy_channel.cmux = circuitmux_alloc();
@@ -2056,6 +2076,7 @@ test_circuitpadding_conditions(void *arg)
 
 
  done:
  done:
   /* XXX: Free everything */
   /* XXX: Free everything */
+  testing_disable_reproducible_rng();
   return;
   return;
 }
 }
 
 
@@ -2385,6 +2406,7 @@ test_circuitpadding_sample_distribution(void *arg)
   /* mock this function so that we dont actually schedule any padding */
   /* mock this function so that we dont actually schedule any padding */
   MOCK(circpad_machine_schedule_padding,
   MOCK(circpad_machine_schedule_padding,
        circpad_machine_schedule_padding_mock);
        circpad_machine_schedule_padding_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Initialize a machine with multiple probability distributions */
   /* Initialize a machine with multiple probability distributions */
   circpad_machines_init();
   circpad_machines_init();
@@ -2417,6 +2439,7 @@ test_circuitpadding_sample_distribution(void *arg)
  done:
  done:
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   UNMOCK(circpad_machine_schedule_padding);
   UNMOCK(circpad_machine_schedule_padding);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 static circpad_decision_t
 static circpad_decision_t
@@ -2442,6 +2465,7 @@ test_circuitpadding_machine_rate_limiting(void *arg)
    * really care about padding counts */
    * really care about padding counts */
   MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
   MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
   MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
   MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
+  testing_enable_reproducible_rng();
 
 
   /* Setup machine and circuits */
   /* Setup machine and circuits */
   client_side = TO_CIRCUIT(origin_circuit_new());
   client_side = TO_CIRCUIT(origin_circuit_new());
@@ -2495,6 +2519,7 @@ test_circuitpadding_machine_rate_limiting(void *arg)
 
 
  done:
  done:
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
   free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /* Test global padding rate limits */
 /* Test global padding rate limits */
@@ -2514,6 +2539,7 @@ test_circuitpadding_global_rate_limiting(void *arg)
   MOCK(circuit_package_relay_cell,
   MOCK(circuit_package_relay_cell,
        circuit_package_relay_cell_mock);
        circuit_package_relay_cell_mock);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
   MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
+  testing_enable_reproducible_rng();
 
 
   monotime_init();
   monotime_init();
   monotime_enable_test_mocking();
   monotime_enable_test_mocking();
@@ -2593,6 +2619,7 @@ test_circuitpadding_global_rate_limiting(void *arg)
   circuitmux_free(dummy_channel.cmux);
   circuitmux_free(dummy_channel.cmux);
   SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
   SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
   smartlist_free(vote1.net_params);
   smartlist_free(vote1.net_params);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /* Test reduced and disabled padding */
 /* Test reduced and disabled padding */
@@ -2603,6 +2630,7 @@ test_circuitpadding_reduce_disable(void *arg)
   int64_t actual_mocked_monotime_start;
   int64_t actual_mocked_monotime_start;
 
 
   MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
   MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
+  testing_enable_reproducible_rng();
 
 
   nodes_init();
   nodes_init();
   dummy_channel.cmux = circuitmux_alloc();
   dummy_channel.cmux = circuitmux_alloc();
@@ -2742,6 +2770,7 @@ test_circuitpadding_reduce_disable(void *arg)
   free_fake_orcirc(relay_side);
   free_fake_orcirc(relay_side);
   circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
   circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
   circuitmux_free(dummy_channel.cmux);
   circuitmux_free(dummy_channel.cmux);
+  testing_disable_reproducible_rng();
 }
 }
 
 
 /** Just a basic machine whose whole purpose is to reach the END state */
 /** Just a basic machine whose whole purpose is to reach the END state */

+ 10 - 19
src/test/test_prob_distr.c

@@ -1119,13 +1119,14 @@ test_psi_dist_sample(const struct dist *dist)
 }
 }
 
 
 static void
 static void
-dump_seed(void)
+write_stochastic_warning(void)
 {
 {
-  printf("\n"
+  if (tinytest_cur_test_has_failed()) {
+    printf("\n"
          "NOTE: This is a stochastic test, and we expect it to fail from\n"
          "NOTE: This is a stochastic test, and we expect it to fail from\n"
          "time to time, with some low probability. If you see it fail more\n"
          "time to time, with some low probability. If you see it fail more\n"
          "than one trial in 100, though, please tell us.\n\n");
          "than one trial in 100, though, please tell us.\n\n");
-  testing_dump_reproducible_rng_seed();
+  }
 }
 }
 
 
 static void
 static void
@@ -1180,7 +1181,7 @@ test_stochastic_uniform(void *arg)
 
 
  done:
  done:
   if (tests_failed) {
   if (tests_failed) {
-    dump_seed();
+    write_stochastic_warning();
   }
   }
   testing_disable_reproducible_rng();
   testing_disable_reproducible_rng();
 }
 }
@@ -1273,7 +1274,7 @@ test_stochastic_genpareto(void *arg)
 
 
  done:
  done:
   if (tests_failed) {
   if (tests_failed) {
-    dump_seed();
+    write_stochastic_warning();
   }
   }
   testing_disable_reproducible_rng();
   testing_disable_reproducible_rng();
 }
 }
@@ -1301,7 +1302,7 @@ test_stochastic_geometric(void *arg)
 
 
  done:
  done:
   if (tests_failed) {
   if (tests_failed) {
-    dump_seed();
+    write_stochastic_warning();
   }
   }
   testing_disable_reproducible_rng();
   testing_disable_reproducible_rng();
 }
 }
@@ -1328,7 +1329,7 @@ test_stochastic_logistic(void *arg)
 
 
  done:
  done:
   if (tests_failed) {
   if (tests_failed) {
-    dump_seed();
+    write_stochastic_warning();
   }
   }
   testing_disable_reproducible_rng();
   testing_disable_reproducible_rng();
 }
 }
@@ -1337,7 +1338,6 @@ static void
 test_stochastic_log_logistic(void *arg)
 test_stochastic_log_logistic(void *arg)
 {
 {
   bool ok = 0;
   bool ok = 0;
-  bool tests_failed = true;
   (void) arg;
   (void) arg;
 
 
   testing_enable_reproducible_rng();
   testing_enable_reproducible_rng();
@@ -1351,12 +1351,8 @@ test_stochastic_log_logistic(void *arg)
   ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2);
   ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2);
   tt_assert(ok);
   tt_assert(ok);
 
 
-  tests_failed = false;
-
  done:
  done:
-  if (tests_failed) {
-    dump_seed();
-  }
+  write_stochastic_warning();
   testing_disable_reproducible_rng();
   testing_disable_reproducible_rng();
 }
 }
 
 
@@ -1364,7 +1360,6 @@ static void
 test_stochastic_weibull(void *arg)
 test_stochastic_weibull(void *arg)
 {
 {
   bool ok = 0;
   bool ok = 0;
-  bool tests_failed = true;
   (void) arg;
   (void) arg;
 
 
   testing_enable_reproducible_rng();
   testing_enable_reproducible_rng();
@@ -1380,12 +1375,8 @@ test_stochastic_weibull(void *arg)
   ok = test_stochastic_weibull_impl(10, 1);
   ok = test_stochastic_weibull_impl(10, 1);
   tt_assert(ok);
   tt_assert(ok);
 
 
-  tests_failed = false;
-
  done:
  done:
-  if (tests_failed) {
-    dump_seed();
-  }
+  write_stochastic_warning();
   testing_disable_reproducible_rng();
   testing_disable_reproducible_rng();
   UNMOCK(crypto_rand);
   UNMOCK(crypto_rand);
 }
 }