|
From: <sv...@va...> - 2015-05-09 21:28:34
|
Author: florian
Date: Sat May 9 22:28:24 2015
New Revision: 15195
Log:
New function VG_(am_resize_client_dataseg) to hide the implementation
details of the brk segment.
Improve memcheck/tests/linux/brk.c testcase.
Modified:
branches/ASPACEM_TWEAKS/coregrind/m_aspacemgr/aspacemgr-linux.c
branches/ASPACEM_TWEAKS/coregrind/m_syswrap/syswrap-generic.c
branches/ASPACEM_TWEAKS/coregrind/pub_core_aspacemgr.h
branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.c
branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.stderr.exp
branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.vgtest
Modified: branches/ASPACEM_TWEAKS/coregrind/m_aspacemgr/aspacemgr-linux.c
==============================================================================
--- branches/ASPACEM_TWEAKS/coregrind/m_aspacemgr/aspacemgr-linux.c (original)
+++ branches/ASPACEM_TWEAKS/coregrind/m_aspacemgr/aspacemgr-linux.c Sat May 9 22:28:24 2015
@@ -2964,6 +2964,71 @@
return VG_(am_mmap_anon_fixed_client)( anon_start, anon_size, prot );
}
+/* Resize the client brk segment from OLDBRK to NEWBRK. Return an error if
+ the resize operation could not be completed. A +1 error core means
+ "overflow", a -1 error code means "underflow", and 0 means some other
+ failure. */
+SysRes VG_(am_resize_client_dataseg) ( Addr oldbrk, Addr newbrk )
+{
+ static Addr brk_base = 0;
+
+ SysRes success = VG_(mk_SysRes_Success)(0);
+
+ if (newbrk == oldbrk) return success; // nothing to do
+
+ /* We rely on the caller to pass in the correct address here. Ideally,
+ we should keep the state (base/limit) in the address space manager and
+ not at the call site. */
+ if (brk_base == 0) brk_base = oldbrk;
+
+ const NSegment *aseg = VG_(am_find_nsegment)(brk_base);
+ aspacem_assert(aseg && aseg->kind == SkAnonC);
+
+ if (newbrk < oldbrk) {
+ /* Shrinking the data segment. Be lazy and don't munmap the
+ excess area. */
+
+ /* Test for underflow. */
+ if (newbrk < brk_base) return VG_(mk_SysRes_Error)(-1);
+
+ /* Since we're being lazy and not unmapping pages, we have to
+ zero out the area, so that if the area later comes back into
+ circulation, it will be filled with zeroes, as if it really
+ had been unmapped and later remapped. Be a bit paranoid and
+ try hard to ensure we're not going to segfault by doing the
+ write - check both ends of the range are in the same segment
+ and that segment is writable. */
+ const NSegment *nseg = VG_(am_find_nsegment)(newbrk);
+ aspacem_assert(nseg == aseg);
+ if (aseg->hasW)
+ VG_(memset)( (void*)newbrk, 0, oldbrk - newbrk );
+
+ return success;
+ }
+
+ /* Otherwise we're expanding the brk segment. */
+ if (newbrk <= aseg->end + 1) {
+ /* Still fits within the anon segment. */
+ return success;
+ }
+
+ Addr newbrkP = VG_PGROUNDUP(newbrk);
+ SizeT delta = newbrkP - (aseg->end + 1);
+ aspacem_assert(delta > 0);
+ aspacem_assert(VG_IS_PAGE_ALIGNED(delta));
+
+ Bool overflow;
+ if (! VG_(am_extend_into_adjacent_reservation_client)( aseg->start, delta,
+ &overflow)) {
+ if (overflow)
+ return VG_(mk_SysRes_Error)(1);
+ else
+ return VG_(mk_SysRes_Error)(0);
+ }
+
+ return success;
+}
+
/* Allocate the client stack segment beginning at STACK_END. The stack segment
can be at most MAX_SIZE bytes large. It is represented as an expandable
Modified: branches/ASPACEM_TWEAKS/coregrind/m_syswrap/syswrap-generic.c
==============================================================================
--- branches/ASPACEM_TWEAKS/coregrind/m_syswrap/syswrap-generic.c (original)
+++ branches/ASPACEM_TWEAKS/coregrind/m_syswrap/syswrap-generic.c Sat May 9 22:28:24 2015
@@ -1187,9 +1187,6 @@
static Addr do_brk ( Addr newbrk, ThreadId tid )
{
- NSegment const* aseg;
- Addr newbrkP;
- SizeT delta;
Bool debug = False;
if (debug)
@@ -1198,76 +1195,37 @@
if (0) VG_(am_show_nsegments)(0, "in_brk");
- if (newbrk < VG_(brk_base))
- /* Clearly impossible. */
- goto bad;
+ /* Special case: a 0 argument means to return the current high water mark */
+ if (newbrk == 0) return VG_(brk_limit);
- if (newbrk < VG_(brk_limit)) {
- /* shrinking the data segment. Be lazy and don't munmap the
- excess area. */
- NSegment const * seg = VG_(am_find_nsegment)(newbrk);
- vg_assert(seg);
-
- if (seg->hasT)
- VG_(discard_translations)( newbrk, VG_(brk_limit) - newbrk,
- "do_brk(shrink)" );
- /* Since we're being lazy and not unmapping pages, we have to
- zero out the area, so that if the area later comes back into
- circulation, it will be filled with zeroes, as if it really
- had been unmapped and later remapped. Be a bit paranoid and
- try hard to ensure we're not going to segfault by doing the
- write - check both ends of the range are in the same segment
- and that segment is writable. */
- NSegment const * seg2;
-
- seg2 = VG_(am_find_nsegment)( VG_(brk_limit) - 1 );
- vg_assert(seg2);
-
- if (seg == seg2 && seg->hasW)
- VG_(memset)( (void*)newbrk, 0, VG_(brk_limit) - newbrk );
-
- VG_(brk_limit) = newbrk;
- return newbrk;
- }
-
- /* otherwise we're expanding the brk segment. */
- if (VG_(brk_limit) > VG_(brk_base))
- aseg = VG_(am_find_nsegment)( VG_(brk_limit)-1 );
- else
- aseg = VG_(am_find_nsegment)( VG_(brk_limit) );
+ SysRes sres = VG_(am_resize_client_dataseg)(VG_(brk_limit), newbrk);
- /* These should be assured by setup_client_dataseg in m_main. */
- vg_assert(aseg);
- vg_assert(aseg->kind == SkAnonC);
-
- if (newbrk <= aseg->end + 1) {
- /* still fits within the anon segment. */
- VG_(brk_limit) = newbrk;
- return newbrk;
- }
-
- newbrkP = VG_PGROUNDUP(newbrk);
- delta = newbrkP - (aseg->end + 1);
- vg_assert(delta > 0);
- vg_assert(VG_IS_PAGE_ALIGNED(delta));
-
- Bool overflow;
- if (! VG_(am_extend_into_adjacent_reservation_client)( aseg->start, delta,
- &overflow)) {
- if (overflow)
+ if (sr_isError(sres)) {
+ if (sr_Err(sres) == 1)
VG_(umsg)("brk segment overflow in thread #%d: can't grow to %#lx\n",
- tid, newbrkP);
+ tid, newbrk);
+ else if (sr_Err(sres) == -1)
+ VG_(umsg)("brk segment underflow in thread #%d: can't shrink to %#lx\n",
+ tid, newbrk);
else
- VG_(umsg)("Cannot map memory to grow brk segment in thread #%d "
- "to %#lx\n", tid, newbrkP);
- goto bad;
+ VG_(umsg)("Cannot map memory to %s brk segment in thread #%d "
+ "to %#lx\n", newbrk > VG_(brk_limit) ? "grow" : "shrink",
+ tid, newbrk);
+ return VG_(brk_limit);
+ }
+
+ /* If the brk segment was shrunk, discard translations if there were any. */
+ if (newbrk < VG_(brk_limit)) {
+ const NSegment *aseg = VG_(am_find_nsegment)(VG_(brk_limit) - 1);
+ vg_assert(aseg);
+
+ if (aseg->hasT)
+ VG_(discard_translations)(newbrk, VG_(brk_limit) - newbrk,
+ "do_brk(shrink)");
}
VG_(brk_limit) = newbrk;
return newbrk;
-
- bad:
- return VG_(brk_limit);
}
Modified: branches/ASPACEM_TWEAKS/coregrind/pub_core_aspacemgr.h
==============================================================================
--- branches/ASPACEM_TWEAKS/coregrind/pub_core_aspacemgr.h (original)
+++ branches/ASPACEM_TWEAKS/coregrind/pub_core_aspacemgr.h Sat May 9 22:28:24 2015
@@ -312,6 +312,7 @@
// Client memory segments
extern SysRes VG_(am_alloc_client_dataseg) ( Addr base, SizeT max_size,
UInt prot );
+extern SysRes VG_(am_resize_client_dataseg) ( Addr oldbrk, Addr newbrk );
extern SysRes VG_(am_alloc_extensible_client_stack) ( Addr stack_end,
SizeT max_size,
UInt prot );
Modified: branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.c
==============================================================================
--- branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.c (original)
+++ branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.c Sat May 9 22:28:24 2015
@@ -11,29 +11,33 @@
int i;
void* orig_ds = sbrk(0);
void* ds = orig_ds;
- void* vals[10];
- void* res __attribute__((unused));
-#define EOL ((void*)( ~(long)0 ))
- vals[0] = (void*)0;
- vals[1] = (void*)1;
- vals[2] = ds - 0x1; // small shrink
- vals[3] = ds;
- vals[4] = ds + 0x1000; // small growth
- vals[5] = ds + 0x40000000; // too-big growth
- vals[6] = ds + 0x500; // shrink a little, but still above start size
- vals[7] = ds - 0x1; // shrink below start size
-// vals[8] = ds - 0x1000; // shrink a lot below start size (into text)
-// vals[9] = EOL;
- vals[8] = EOL;
+ struct {
+ void *brkval;
+ const char *what;
+ } vals[] = {
+ { (void *)0, "like sbrk(0)" },
+ { (void *)1, "shrink to 0x1 --> expect underflow" },
+ { ds - 0x1, "shrink just below current brk value --> expect underflow" },
+ { ds, "brk to current brk value" },
+ { ds + 0x1000,"grow by 0x1000" },
+ { ds + 0x40000000, "excessive growth --> expect overflow" },
+ { ds + 0x200, "shrink by 0x800" },
+ };
- for (i = 0; EOL != vals[i]; i++) {
- res = (void*)syscall(__NR_brk, vals[i]);
+ fprintf(stderr, "KERNEL __NR_brk\n");
+ for (i = 0; i < sizeof vals / sizeof vals[0]; i++) {
+ fprintf(stderr, "...%s\n", vals[i].what);
+ void *res = (void*)syscall(__NR_brk, vals[i].brkval);
+ fprintf(stderr, "res = %p\n", res);
}
+ fprintf(stderr, "LIBC brk\n");
assert( 0 == brk(orig_ds) ); // libc brk()
- for (i = 0; EOL != vals[i]; i++) {
- res = (void*)(long)brk(vals[i]);
+ for (i = 0; i < sizeof vals / sizeof vals[0]; i++) {
+ fprintf(stderr, "...%s\n", vals[i].what);
+ int rc = brk(vals[i].brkval);
+ fprintf(stderr, "rc = %d\n", rc);
}
return 0;
Modified: branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.stderr.exp
==============================================================================
--- branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.stderr.exp (original)
+++ branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.stderr.exp Sat May 9 22:28:24 2015
@@ -1,12 +1,36 @@
-
+KERNEL __NR_brk
+...like sbrk(0)
+res = 0x........
+...shrink to 0x........ --> expect underflow
+brk segment underflow in thread #1: can't shrink to 0x........
+res = 0x........
+...shrink just below current brk value --> expect underflow
+brk segment underflow in thread #1: can't shrink to 0x........
+res = 0x........
+...brk to current brk value
+res = 0x........
+...grow by 0x........
+res = 0x........
+...excessive growth --> expect overflow
brk segment overflow in thread #1: can't grow to 0x........
+res = 0x........
+...shrink by 0x........
+res = 0x........
+LIBC brk
+...like sbrk(0)
+rc = 0
+...shrink to 0x........ --> expect underflow
+brk segment underflow in thread #1: can't shrink to 0x........
+rc = 0
+...shrink just below current brk value --> expect underflow
+brk segment underflow in thread #1: can't shrink to 0x........
+rc = 0
+...brk to current brk value
+rc = 0
+...grow by 0x........
+rc = 0
+...excessive growth --> expect overflow
brk segment overflow in thread #1: can't grow to 0x........
-
-HEAP SUMMARY:
- in use at exit: ... bytes in ... blocks
- total heap usage: ... allocs, ... frees, ... bytes allocated
-
-For a detailed leak analysis, rerun with: --leak-check=full
-
-For counts of detected and suppressed errors, rerun with: -v
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+rc = -1
+...shrink by 0x........
+rc = 0
Modified: branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.vgtest
==============================================================================
--- branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.vgtest (original)
+++ branches/ASPACEM_TWEAKS/memcheck/tests/linux/brk.vgtest Sat May 9 22:28:24 2015
@@ -1,2 +1,3 @@
prog: brk
+vgopts: -q
stderr_filter: ../filter_allocs
|