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.
This commit is contained in:
Wilco Dijkstra 2017-10-19 18:19:55 +01:00
parent 4d916f0f12
commit d74e6f6c0d
2 changed files with 16 additions and 9 deletions

View File

@ -1,3 +1,7 @@
2017-10-19 Wilco Dijkstra <wdijkstr@arm.com>
* malloc/malloc.c (_int_free): Fix deadlock bug in consistency check.
2017-10-19 Valery Reznic <valery_reznic@yahoo.com> 2017-10-19 Valery Reznic <valery_reznic@yahoo.com>
H.J. Lu <hongjiu.lu@intel.com> H.J. Lu <hongjiu.lu@intel.com>

View File

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