public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 4/5] Fix deadlock in _int_free consistency check
@ 2017-10-12  9:35 Wilco Dijkstra
  2017-10-12 10:01 ` Andreas Schwab
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Wilco Dijkstra @ 2017-10-12  9:35 UTC (permalink / raw)
  To: libc-alpha; +Cc: nd

This patch fixes a deadlock in the fastbin consistency check.
If we fail the fast check due to concurrent modifications to
the next chunk or system_mem, we should not lock if we already
have the arena lock.  Simplify the check to make it obviously
correct.

Passes GLIBC tests, OK for commit?

ChangeLog:
2017-10-11  Wilco Dijkstra  <wdijkstr@arm.com>

	* malloc/malloc.c (_int_free): Fix deadlock bug.
--

diff --git a/malloc/malloc.c b/malloc/malloc.c
index c00df205c6004ee5b5d0aee9ffd5130b3c8f9e9f..f4f44400d120188c4d0bece996380e04b35c8fac 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -4168,15 +4168,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
 			     >= av->system_mem, 0))
       {
 	/* We might not have a lock at this point and concurrent modifications
-	   of system_mem might have let to a false positive.  Redo the test
-	   after getting the lock.  */
-	if (!have_lock
-	    || ({ __libc_lock_lock (av->mutex);
-		  chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
-		  || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
-	        }))
+	   of system_mem might result in a false positive.  Redo the test after
+	   getting the lock.  */
+	if (!have_lock)
+	  __libc_lock_lock (av->mutex);
+	if (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
+	    || chunksize (chunk_at_offset (p, size)) >= av->system_mem)
 	  malloc_printerr ("free(): invalid next size (fast)");
-	if (! have_lock)
+	if (!have_lock)
 	  __libc_lock_unlock (av->mutex);
       }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12  9:35 [PATCH 4/5] Fix deadlock in _int_free consistency check Wilco Dijkstra
@ 2017-10-12 10:01 ` Andreas Schwab
  2017-10-12 10:41   ` Wilco Dijkstra
  2017-10-12 10:06 ` Florian Weimer
  2017-10-12 20:49 ` DJ Delorie
  2 siblings, 1 reply; 15+ messages in thread
From: Andreas Schwab @ 2017-10-12 10:01 UTC (permalink / raw)
  To: Wilco Dijkstra; +Cc: libc-alpha, nd

On Okt 12 2017, Wilco Dijkstra <Wilco.Dijkstra@arm.com> wrote:

> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index c00df205c6004ee5b5d0aee9ffd5130b3c8f9e9f..f4f44400d120188c4d0bece996380e04b35c8fac 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -4168,15 +4168,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
>  			     >= av->system_mem, 0))
>        {
>  	/* We might not have a lock at this point and concurrent modifications
> -	   of system_mem might have let to a false positive.  Redo the test
> -	   after getting the lock.  */
> -	if (!have_lock
> -	    || ({ __libc_lock_lock (av->mutex);
> -		  chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
> -		  || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
> -	        }))
> +	   of system_mem might result in a false positive.  Redo the test after
> +	   getting the lock.  */
> +	if (!have_lock)
> +	  __libc_lock_lock (av->mutex);
> +	if (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
> +	    || chunksize (chunk_at_offset (p, size)) >= av->system_mem)

There is no need to redo the tests if we had the lock.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12  9:35 [PATCH 4/5] Fix deadlock in _int_free consistency check Wilco Dijkstra
  2017-10-12 10:01 ` Andreas Schwab
@ 2017-10-12 10:06 ` Florian Weimer
  2017-10-12 10:16   ` Andreas Schwab
  2017-10-12 10:18   ` Wilco Dijkstra
  2017-10-12 20:49 ` DJ Delorie
  2 siblings, 2 replies; 15+ messages in thread
From: Florian Weimer @ 2017-10-12 10:06 UTC (permalink / raw)
  To: Wilco Dijkstra, libc-alpha; +Cc: nd

On 10/12/2017 11:35 AM, Wilco Dijkstra wrote:
> This patch fixes a deadlock in the fastbin consistency check.
> If we fail the fast check due to concurrent modifications to
> the next chunk or system_mem, we should not lock if we already
> have the arena lock.  Simplify the check to make it obviously
> correct.

I don't think the subject line is correct.  What is the deadlock?  I 
don't see it.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 10:06 ` Florian Weimer
@ 2017-10-12 10:16   ` Andreas Schwab
  2017-10-12 10:49     ` Florian Weimer
  2017-10-12 10:18   ` Wilco Dijkstra
  1 sibling, 1 reply; 15+ messages in thread
From: Andreas Schwab @ 2017-10-12 10:16 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Wilco Dijkstra, libc-alpha, nd

On Okt 12 2017, Florian Weimer <fweimer@redhat.com> wrote:

> On 10/12/2017 11:35 AM, Wilco Dijkstra wrote:
>> This patch fixes a deadlock in the fastbin consistency check.
>> If we fail the fast check due to concurrent modifications to
>> the next chunk or system_mem, we should not lock if we already
>> have the arena lock.  Simplify the check to make it obviously
>> correct.
>
> I don't think the subject line is correct.  What is the deadlock?  I don't
> see it.

The problem is that commit 24cffce736 inverted the condition on
have_lock, which is wrong.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 10:06 ` Florian Weimer
  2017-10-12 10:16   ` Andreas Schwab
@ 2017-10-12 10:18   ` Wilco Dijkstra
  2017-10-12 10:54     ` Florian Weimer
  1 sibling, 1 reply; 15+ messages in thread
From: Wilco Dijkstra @ 2017-10-12 10:18 UTC (permalink / raw)
  To: Florian Weimer, libc-alpha; +Cc: nd

Florian Weimer wrote:
    
> I don't think the subject line is correct.  What is the deadlock?  I 
> don't see it.

> -	if (!have_lock
> -	    || ({ __libc_lock_lock (av->mutex);

It's right there. Have_lock means you've just done __libc_lock_lock (av->mutex),
so doing it again (same thread) implies deadlock.

Wilco

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 10:01 ` Andreas Schwab
@ 2017-10-12 10:41   ` Wilco Dijkstra
  2017-10-12 10:47     ` Andreas Schwab
  0 siblings, 1 reply; 15+ messages in thread
From: Wilco Dijkstra @ 2017-10-12 10:41 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-alpha, nd

Andreas Schwab wrote:

> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index c00df205c6004ee5b5d0aee9ffd5130b3c8f9e9f..f4f44400d120188c4d0bece996380e04b35c8fac 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -4168,15 +4168,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
>                             >= av->system_mem, 0))
>        {
>        /* We might not have a lock at this point and concurrent modifications
> -        of system_mem might have let to a false positive.  Redo the test
> -        after getting the lock.  */
> -     if (!have_lock
> -         || ({ __libc_lock_lock (av->mutex);
> -               chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
> -               || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
> -             }))
> +        of system_mem might result in a false positive.  Redo the test after
> +        getting the lock.  */
> +     if (!have_lock)
> +       __libc_lock_lock (av->mutex);
> +     if (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
> +         || chunksize (chunk_at_offset (p, size)) >= av->system_mem)

> There is no need to redo the tests if we had the lock.

Well I guess an alternative is to do:

if (have_lock)
   print error
else
{
  lock
  repeat test and print error
  unlock
}

I also wonder whether we should actually unlock again before printing the error -
or do we assume/hope/know no memory allocation is ever required in the error case?

Wilco

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 10:41   ` Wilco Dijkstra
@ 2017-10-12 10:47     ` Andreas Schwab
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Schwab @ 2017-10-12 10:47 UTC (permalink / raw)
  To: Wilco Dijkstra; +Cc: libc-alpha, nd

On Okt 12 2017, Wilco Dijkstra <Wilco.Dijkstra@arm.com> wrote:

> Andreas Schwab wrote:
>
>> diff --git a/malloc/malloc.c b/malloc/malloc.c
>> index c00df205c6004ee5b5d0aee9ffd5130b3c8f9e9f..f4f44400d120188c4d0bece996380e04b35c8fac 100644
>> --- a/malloc/malloc.c
>> +++ b/malloc/malloc.c
>> @@ -4168,15 +4168,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
>>                             >= av->system_mem, 0))
>>        {
>>        /* We might not have a lock at this point and concurrent modifications
>> -        of system_mem might have let to a false positive.  Redo the test
>> -        after getting the lock.  */
>> -     if (!have_lock
>> -         || ({ __libc_lock_lock (av->mutex);
>> -               chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
>> -               || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
>> -             }))
>> +        of system_mem might result in a false positive.  Redo the test after
>> +        getting the lock.  */
>> +     if (!have_lock)
>> +       __libc_lock_lock (av->mutex);
>> +     if (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
>> +         || chunksize (chunk_at_offset (p, size)) >= av->system_mem)
>
>> There is no need to redo the tests if we had the lock.
>
> Well I guess an alternative is to do:
>
> if (have_lock)
>    print error
> else
> {
>   lock
>   repeat test and print error
>   unlock
> }

No, you can just test have_lock again, and skip the redo if set.  Still
much clearer than the original layout.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 10:16   ` Andreas Schwab
@ 2017-10-12 10:49     ` Florian Weimer
  0 siblings, 0 replies; 15+ messages in thread
From: Florian Weimer @ 2017-10-12 10:49 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Wilco Dijkstra, libc-alpha, nd

On 10/12/2017 12:16 PM, Andreas Schwab wrote:
> On Okt 12 2017, Florian Weimer <fweimer@redhat.com> wrote:
> 
>> On 10/12/2017 11:35 AM, Wilco Dijkstra wrote:
>>> This patch fixes a deadlock in the fastbin consistency check.
>>> If we fail the fast check due to concurrent modifications to
>>> the next chunk or system_mem, we should not lock if we already
>>> have the arena lock.  Simplify the check to make it obviously
>>> correct.
>>
>> I don't think the subject line is correct.  What is the deadlock?  I don't
>> see it.
> 
> The problem is that commit 24cffce736 inverted the condition on
> have_lock, which is wrong.

Oh, right, sorry about that.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 10:18   ` Wilco Dijkstra
@ 2017-10-12 10:54     ` Florian Weimer
  0 siblings, 0 replies; 15+ messages in thread
From: Florian Weimer @ 2017-10-12 10:54 UTC (permalink / raw)
  To: Wilco Dijkstra, libc-alpha; +Cc: nd

On 10/12/2017 12:18 PM, Wilco Dijkstra wrote:
> Florian Weimer wrote:
>      
>> I don't think the subject line is correct.  What is the deadlock?  I
>> don't see it.
> 
>> -	if (!have_lock
>> -	    || ({ __libc_lock_lock (av->mutex);
> 
> It's right there. Have_lock means you've just done __libc_lock_lock (av->mutex),
> so doing it again (same thread) implies deadlock.

Hmm.

So if we enter this code path with have_lock, we don't have to re-do the 
check, but malloc_printerr will be called in the end anyway, so this is 
not the interesting case.

In practice, without heap corruption, the lock will be acquired here and 
re-checking is needed, so I think your cleanup is okay after all.  The 
logic is indeed much clearer.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12  9:35 [PATCH 4/5] Fix deadlock in _int_free consistency check Wilco Dijkstra
  2017-10-12 10:01 ` Andreas Schwab
  2017-10-12 10:06 ` Florian Weimer
@ 2017-10-12 20:49 ` DJ Delorie
  2017-10-12 21:35   ` Wilco Dijkstra
  2 siblings, 1 reply; 15+ messages in thread
From: DJ Delorie @ 2017-10-12 20:49 UTC (permalink / raw)
  To: Wilco Dijkstra; +Cc: libc-alpha, nd


I think the bug can be fixed by only changing the sense of the have_lock
condition:

> -	if (!have_lock
> +	if (have_lock

The code around this patch looks like

 if (error detected)
   {
     /* patch goes here */
     print error message
   }

What we *want* is

 if (error detected)
   {
     if (didn't have lock)
        get lock, redo test
     print error message if still an error
   }

so...

 if (error detected)
   {
     if (have_lock)
       /* we had the lock during the test above, so the test is valid,
          and the error we detect is valid.  */
       print error message
     else
       /* we didn't have the lock, so aquire it and repeat the test.  If
          the error is still present, fail.  */
       get lock, repeat test, maybe print error message
   }

which reduces to


 if (error detected)
   {
     if (have_lock /* in which case, above test is usable as-is, it's an error */
         OR (get lock, repeat test, still an error))
       print error message
   }

Which is what the current upstream code is, except for the sense of the
have_lock test.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 20:49 ` DJ Delorie
@ 2017-10-12 21:35   ` Wilco Dijkstra
  2017-10-17 10:03     ` Florian Weimer
  0 siblings, 1 reply; 15+ messages in thread
From: Wilco Dijkstra @ 2017-10-12 21:35 UTC (permalink / raw)
  To: DJ Delorie; +Cc: libc-alpha, nd

DJ Delorie wrote:
> I think the bug can be fixed by only changing the sense of the have_lock
> condition:

> -     if (!have_lock
> +     if (have_lock

Yes it could but then it's still impossible to follow the logic... The only reason
I spotted the bug was because I refactored the code. Then the bug suddenly
became very obvious. I think locking as a side effect in conditions is something
we should avoid.

So my variant or this one are reasonable ways to do it:

 if (error detected)
   {
     if (have_lock)
       /* we had the lock during the test above, so the test is valid,
          and the error we detect is valid.  */
       print error message
     else
       /* we didn't have the lock, so aquire it and repeat the test.  If
          the error is still present, fail.  */
       get lock, repeat test, maybe print error message
   }

I suppose we could also print the error once at the end:

if (error detected)
{
  bool fail = true;
  if (!have_lock)
  {
     get_lock
     fail = repeat test
     unlock
  }
  if (fail)
    print error
}

Wilco

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-12 21:35   ` Wilco Dijkstra
@ 2017-10-17 10:03     ` Florian Weimer
  2017-10-17 10:49       ` Wilco Dijkstra
  0 siblings, 1 reply; 15+ messages in thread
From: Florian Weimer @ 2017-10-17 10:03 UTC (permalink / raw)
  To: Wilco Dijkstra, DJ Delorie; +Cc: libc-alpha, nd

On 10/12/2017 11:35 PM, Wilco Dijkstra wrote:
> I suppose we could also print the error once at the end:
> 
> if (error detected)
> {
>    bool fail = true;
>    if (!have_lock)
>    {
>       get_lock
>       fail = repeat test
>       unlock
>    }
>    if (fail)
>      print error
> }

Yes, that's also a good option.

Anyway, should I make the one-character change removing the ! in the 
meantime?  This is a real bug, and we should fix that even if the code 
still isn't as pretty as it could be.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-17 10:03     ` Florian Weimer
@ 2017-10-17 10:49       ` Wilco Dijkstra
  2017-10-17 18:17         ` DJ Delorie
  0 siblings, 1 reply; 15+ messages in thread
From: Wilco Dijkstra @ 2017-10-17 10:49 UTC (permalink / raw)
  To: Florian Weimer, DJ Delorie; +Cc: libc-alpha, nd

Florian Weimer wrote:
>
> Anyway, should I make the one-character change removing the ! in the 
> meantime?  This is a real bug, and we should fix that even if the code 
> still isn't as pretty as it could be.

I could easily commit the current patch as is if you're thinking of backporting it.

Once we agree on what the best way of writing this sequence, I can
provide an updated patch.

Wilco
 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-17 10:49       ` Wilco Dijkstra
@ 2017-10-17 18:17         ` DJ Delorie
  2017-10-19 17:26           ` Wilco Dijkstra
  0 siblings, 1 reply; 15+ messages in thread
From: DJ Delorie @ 2017-10-17 18:17 UTC (permalink / raw)
  To: Wilco Dijkstra; +Cc: fweimer, libc-alpha, nd


Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> I could easily commit the current patch as is if you're thinking of backporting it.
>
> Once we agree on what the best way of writing this sequence, I can
> provide an updated patch.

Either way is ok with me, with suitable comments to explain the logic to
the next person who stumbles upon it and is confused :-)

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] Fix deadlock in _int_free consistency check
  2017-10-17 18:17         ` DJ Delorie
@ 2017-10-19 17:26           ` Wilco Dijkstra
  0 siblings, 0 replies; 15+ messages in thread
From: Wilco Dijkstra @ 2017-10-19 17:26 UTC (permalink / raw)
  To: DJ Delorie; +Cc: fweimer, libc-alpha, nd

OK, I've committed this:

Author: Wilco Dijkstra <wdijkstr@arm.com>
Date:   Thu Oct 19 18:19:55 2017 +0100

    Fix deadlock in _int_free consistency check
    
    This patch fixes a deadlock in the fastbin consistency check.
    If we fail the fast check due to concurrent modifications to
    the next chunk or system_mem, we should not lock if we already
    have the arena lock.  Simplify the check to make it obviously
    correct.
    
        * malloc/malloc.c (_int_free): Fix deadlock bug in consistency check.

--
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 784f401b02f7d812936c013632478445ce0773b1..f9054dcea039fc1ecb2456c5c63057ede7a57bfa 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -4171,17 +4171,20 @@ _int_free (mstate av, mchunkptr p, int have_lock)
 	|| __builtin_expect (chunksize (chunk_at_offset (p, size))
 			     >= av->system_mem, 0))
       {
+	bool fail = true;
 	/* We might not have a lock at this point and concurrent modifications
-	   of system_mem might have let to a false positive.  Redo the test
-	   after getting the lock.  */
-	if (!have_lock
-	    || ({ __libc_lock_lock (av->mutex);
-		  chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
-		  || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
-	        }))
+	   of system_mem might result in a false positive.  Redo the test after
+	   getting the lock.  */
+	if (!have_lock)
+	  {
+	    __libc_lock_lock (av->mutex);
+	    fail = (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
+		    || chunksize (chunk_at_offset (p, size)) >= av->system_mem);
+	    __libc_lock_unlock (av->mutex);
+	  }
+
+	if (fail)
 	  malloc_printerr ("free(): invalid next size (fast)");
-	if (! have_lock)
-	  __libc_lock_unlock (av->mutex);
       }
 
     free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);

    

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-10-19 17:26 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-12  9:35 [PATCH 4/5] Fix deadlock in _int_free consistency check Wilco Dijkstra
2017-10-12 10:01 ` Andreas Schwab
2017-10-12 10:41   ` Wilco Dijkstra
2017-10-12 10:47     ` Andreas Schwab
2017-10-12 10:06 ` Florian Weimer
2017-10-12 10:16   ` Andreas Schwab
2017-10-12 10:49     ` Florian Weimer
2017-10-12 10:18   ` Wilco Dijkstra
2017-10-12 10:54     ` Florian Weimer
2017-10-12 20:49 ` DJ Delorie
2017-10-12 21:35   ` Wilco Dijkstra
2017-10-17 10:03     ` Florian Weimer
2017-10-17 10:49       ` Wilco Dijkstra
2017-10-17 18:17         ` DJ Delorie
2017-10-19 17:26           ` Wilco Dijkstra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).