[PATCH] tst-safe-linking: make false positives even more improbable

Carlos O'Donell carlos@redhat.com
Fri Jul 16 20:36:50 GMT 2021


On 7/12/21 11:34 AM, Siddhesh Poyarekar via Libc-alpha wrote:
> There is a 1 in 16 chance of a corruption escaping safe-linking and to
> guard against spurious failures, tst-safe-linking runs each subtest 10
> times to ensure that the chance is reduced to 1 in 2^40.  However, in
> the 1 in 16 chance that a corruption does escape safe linking, it
> could well be caught by other sanity checks we do in malloc, which
> then results in spurious test failures like below:
> 
> test test_fastbin_consolidate failed with a different error
>   expected: malloc_consolidate(): unaligned fastbin chunk detected
> 
>   actual:   malloc_consolidate(): invalid chunk size
> 
> This failure is seen more frequently on i686; I was able to reproduce
> it in about 5 min of running it in a loop.
> 
> Guard against such failures by recording them and retrying the test.
> Also, do not fail the test if we happened to get defeated by the 1 in
> 2^40 odds if in at least one of the instances it was detected by other
> checks.
> 
> Finally, bolster the odds to 2^64 by running 16 times instead of 10.
> The test still has a chance (about 1 in 2^40) of failure so it is
> still flaky in theory.  However in practice if we see a failure here
> then it's more likely that there's a bug than it being an issue with
> the test.  Add more printfs and also dump them to stdout so that in
> the event the test actually fails, we will have some data to try and
> understand why it may have failed.

OK for 2.34.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  malloc/tst-safe-linking.c | 31 +++++++++++++++++++++++++------
>  1 file changed, 25 insertions(+), 6 deletions(-)
> 
> diff --git a/malloc/tst-safe-linking.c b/malloc/tst-safe-linking.c
> index 97cc108be6..959ba59704 100644
> --- a/malloc/tst-safe-linking.c
> +++ b/malloc/tst-safe-linking.c
> @@ -33,32 +33,39 @@ check (const char *test, void (*callback) (void *),
>         const char *expected)
>  {
>    int i, rand_mask;
> -  bool success = false;
> +  int success = 0;	/* 0 == fail, 1 == other check 2 == safe linking */

OK.

>    /* There is a chance of 1/16 that a corrupted pointer will be aligned.
>       Try multiple times so that statistical failure will be improbable.  */
> -  for (i = 0; i < 10 && !success; ++i)
> +  for (i = 0; i < 16; ++i)

OK. Iterate a little more.

>      {
>        rand_mask = rand () & 0xFF;
>        struct support_capture_subprocess result
>  	= support_capture_subprocess (callback, &rand_mask);
> +      printf ("%s\n", result.out.buffer);

OK. A little more verbose.

>        /* Did not crash, could happen.  Try again.  */
>        if (strlen (result.err.buffer) == 0)
>  	continue;
> -      /* Crashed, must be the expected result.  */
> +      /* Crashed, it may either be safe linking or some other check.  If it's
> +	 not safe linking then try again.  */
>        if (strcmp (result.err.buffer, expected) != 0)
>  	{
> -	  support_record_failure ();

OK. Don't record a failure.

> -	  printf ("error: test %s unexpected standard error data\n"
> +	  printf ("test %s failed with a different error\n"
>  	          "  expected: %s\n"
>  	          "  actual:   %s\n",
>  	          test, expected, result.err.buffer);
> +	  success = 1;

OK. Some other malloc check caught the failure.

> +	  continue;
>  	}
>        TEST_VERIFY (WIFSIGNALED (result.status));
>        if (WIFSIGNALED (result.status))
>  	TEST_VERIFY (WTERMSIG (result.status) == SIGABRT);
>        support_capture_subprocess_free (&result);
> -      success = true;
> +      success = 2;

OK. safe-linking caught the failure.

> +      break;
>      }
> +  /* The test fails only if the corruption was not caught by any of the malloc
> +     mechanisms in all those iterations.  This has a lower than 1 in 2^64
> +     chance of a false positive.  */
>    TEST_VERIFY (success);
>  }
>  
> @@ -74,10 +81,13 @@ test_tcache (void *closure)
>    int mask = ((int *)closure)[0];
>    size_t size = TCACHE_ALLOC_SIZE;
>  
> +  printf ("++ tcache ++\n");
> +
>    /* Populate the tcache list.  */
>    void * volatile a = malloc (size);
>    void * volatile b = malloc (size);
>    void * volatile c = malloc (size);
> +  printf ("a=%p, b=%p, c=%p\n", a, b, c);
>    free (a);
>    free (b);
>    free (c);
> @@ -88,6 +98,7 @@ test_tcache (void *closure)
>    printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
>  
>    c = malloc (size);
> +  printf ("Allocated: c=%p\n", c);
>    /* This line will trigger the Safe-Linking check.  */
>    b = malloc (size);
>    printf ("b=%p\n", b);
> @@ -101,10 +112,13 @@ test_fastbin (void *closure)
>    int mask = ((int *)closure)[0];
>    size_t size = TCACHE_ALLOC_SIZE;
>  
> +  printf ("++ fastbin ++\n");
> +
>    /* Take the tcache out of the game.  */
>    for (i = 0; i < TCACHE_FILL_COUNT; ++i)
>      {
>        void * volatile p = calloc (1, size);
> +      printf ("p=%p\n", p);
>        free (p);
>      }
>  
> @@ -112,6 +126,7 @@ test_fastbin (void *closure)
>    void * volatile a = calloc (1, size);
>    void * volatile b = calloc (1, size);
>    void * volatile c = calloc (1, size);
> +  printf ("a=%p, b=%p, c=%p\n", a, b, c);
>    free (a);
>    free (b);
>    free (c);
> @@ -122,6 +137,7 @@ test_fastbin (void *closure)
>    printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
>  
>    c = calloc (1, size);
> +  printf ("Allocated: c=%p\n", c);
>    /* This line will trigger the Safe-Linking check.  */
>    b = calloc (1, size);
>    printf ("b=%p\n", b);
> @@ -135,6 +151,8 @@ test_fastbin_consolidate (void *closure)
>    int mask = ((int*)closure)[0];
>    size_t size = TCACHE_ALLOC_SIZE;
>  
> +  printf ("++ fastbin consolidate ++\n");
> +
>    /* Take the tcache out of the game.  */
>    for (i = 0; i < TCACHE_FILL_COUNT; ++i)
>      {
> @@ -146,6 +164,7 @@ test_fastbin_consolidate (void *closure)
>    void * volatile a = calloc (1, size);
>    void * volatile b = calloc (1, size);
>    void * volatile c = calloc (1, size);
> +  printf ("a=%p, b=%p, c=%p\n", a, b, c);

OK.

>    free (a);
>    free (b);
>    free (c);
> 


-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list