|
From: Paul M. <pa...@sa...> - 2004-09-02 23:46:27
|
A user just hit a problem where stage2 would segfault very early when
using the addrcheck tool. He reported it to me because he was using
my PPC port, but in fact I think it is unrelated to PPC. It is
related to running with VG_(valgrind_base) = 0x70000000. We are
ending up with VG_(shadow_end) = 0x70001000, and we therefore lose the
mapping of the first page of stage2, and things go bad.
The problem is in layout_remaining_space. We set
client_size = ROUNDDN((VG_(valgrind_base)-REDZONE_SIZE) / (1.+ratio),
CLIENT_SIZE_MULTIPLE);
and then
shadow_size = PGROUNDUP(client_size * ratio);
and we have REDZONE_SIZE and CLIENT_SIZE_MULTIPLE both set to 1MB.
With addrcheck we have ratio = 0.125.
Now it turns out that 0x6ff is a multiple of 9, so
(VG_(valgrind_base) - REDZONE_SIZE) / (1. + ratio)
is a multiple of 1MB, in fact 0x63800000, and client_size * ratio is
0xc700000. Then when we do the PGROUNDUP, we end up with an
expression like
(Addr)((client_size * ratio) + (1 << 12) - 1)
This should give 0x70000fff. However, since ratio is declared as a
float, gcc does this computation in single-precision, which doesn't
have enough bits to represent this properly, and so it gets rounded to
0x70001000.
This doesn't happen with VG_(valgrind_base) = 0xb0000000, because
0xaff is not a multiple of 9, and thus the ROUNDDN reduces client_size
enough that the rounding error in calculating client_size * ratio +
4095 doesn't matter.
One fix is to change ratio to a double. But it seems to me that the
second floating-point computation is unnecessary. Is there any good
reason why we don't just set VG_(shadow_end) = VG_(valgrind_base) and
work out shadow_size from that? The patch below does that, and fixes
the user's problem.
Paul.
diff -urN valgrind-2.2.0-ppc/coregrind/vg_main.c valgrind-pie/coregrind/vg_main.c
--- valgrind-2.2.0-ppc/coregrind/vg_main.c 2004-08-31 08:02:50.000000000 +1000
+++ valgrind-pie/coregrind/vg_main.c 2004-09-02 23:14:12.648769024 +1000
@@ -439,9 +439,9 @@
/* where !FIXED mmap goes */
VG_(client_mapbase) = PGROUNDDN((addr_t)(client_size * CLIENT_HEAP_PROPORTION));
- shadow_size = PGROUNDUP(client_size * ratio);
VG_(shadow_base) = VG_(client_end) + REDZONE_SIZE;
- VG_(shadow_end) = VG_(shadow_base) + shadow_size;
+ VG_(shadow_end) = VG_(valgrind_base);
+ shadow_size = VG_(valgrind_base) - VG_(shadow_base);
#define SEGSIZE(a,b) ((VG_(b) - VG_(a))/(1024*1024))
|