1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2025-01-10 19:23:41 +01:00

Fix a race condition in dwarf unwinding.

Original code was accessing rs_cache memory without holding a lock
in some cases. If there was sufficient cache pressure, entry being
accessed may be overwritten by another thread, resulting in a data
race.

We now make a thread local copy of the data, before releasing the
lock. If we end up supporting UNW_CACHE_PER_THREAD properly
in the future, this memcpy should be unnecessary.
This commit is contained in:
Paul Pluzhnikov 2009-11-24 15:18:48 -08:00 committed by Arun Sharma
parent 890a630d76
commit 9626d66019
3 changed files with 1512 additions and 4 deletions

View file

@ -784,7 +784,7 @@ HIDDEN int
dwarf_find_save_locs (struct dwarf_cursor *c) dwarf_find_save_locs (struct dwarf_cursor *c)
{ {
dwarf_state_record_t sr; dwarf_state_record_t sr;
dwarf_reg_state_t *rs; dwarf_reg_state_t *rs, rs_copy;
struct dwarf_rs_cache *cache; struct dwarf_rs_cache *cache;
int ret = 0; int ret = 0;
intrmask_t saved_mask; intrmask_t saved_mask;
@ -796,7 +796,7 @@ dwarf_find_save_locs (struct dwarf_cursor *c)
rs = rs_lookup(cache, c); rs = rs_lookup(cache, c);
if (rs) if (rs)
c->ret_addr_column = rs->ret_addr_column; c->ret_addr_column = rs->ret_addr_column;
else else
{ {
if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 || if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 ||
@ -816,8 +816,9 @@ dwarf_find_save_locs (struct dwarf_cursor *c)
put_unwind_info (c, &c->pi); put_unwind_info (c, &c->pi);
} }
memcpy (&rs_copy, rs, sizeof (rs_copy));
put_rs_cache (c->as, cache, &saved_mask); put_rs_cache (c->as, cache, &saved_mask);
if ((ret = apply_reg_state (c, rs)) < 0) if ((ret = apply_reg_state (c, &rs_copy)) < 0)
return ret; return ret;
return 0; return 0;

View file

@ -41,7 +41,7 @@ endif #ARCH_IA64
Gtest-dyn1 Ltest-dyn1 \ Gtest-dyn1 Ltest-dyn1 \
test-async-sig test-flush-cache test-init-remote \ test-async-sig test-flush-cache test-init-remote \
test-mem test-setjmp test-ptrace \ test-mem test-setjmp test-ptrace \
Ltest-nomalloc Ltest-nomalloc rs-race
noinst_PROGRAMS_cdep = forker mapper test-ptrace-misc test-varargs \ noinst_PROGRAMS_cdep = forker mapper test-ptrace-misc test-varargs \
Gperf-simple Lperf-simple Gperf-simple Lperf-simple
@ -99,6 +99,7 @@ test_ptrace_LDADD = ../src/libunwind-ptrace.a $(LIBUNWIND)
Ltest_concurrent_LDADD = $(LIBUNWIND) -lpthread Ltest_concurrent_LDADD = $(LIBUNWIND) -lpthread
Gtest_concurrent_LDADD = $(LIBUNWIND) -lpthread Gtest_concurrent_LDADD = $(LIBUNWIND) -lpthread
test_async_sig_LDADD = $(LIBUNWIND) -lpthread test_async_sig_LDADD = $(LIBUNWIND) -lpthread
rs_race_LDADD = $(LIBUNWIND) -lpthread
LDADD += -ldl LDADD += -ldl
Ltest_nomalloc_SOURCES = Ltest-nomalloc.c Ltest_nomalloc_SOURCES = Ltest-nomalloc.c

1506
tests/rs-race.c Normal file

File diff suppressed because it is too large Load diff