Fix nasty use after free bug revealed by last munmap fix.
Unexport split_segment; it isn't needed elsewhere.
(Something still wrong with munmap.)


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2143 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index 5878826..0ce9b13 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -1580,7 +1580,6 @@
 
 extern Segment *VG_(find_segment)(Addr a);
 extern Segment *VG_(next_segment)(Segment *);
-extern Segment *VG_(split_segment)(Addr a);
 
 extern Bool     VG_(seg_contains)(const Segment *s, Addr ptr, UInt size);
 extern Bool     VG_(seg_overlaps)(const Segment *s, Addr ptr, UInt size);
diff --git a/coregrind/vg_memory.c b/coregrind/vg_memory.c
index 3a50975..c8b42ba 100644
--- a/coregrind/vg_memory.c
+++ b/coregrind/vg_memory.c
@@ -142,6 +142,9 @@
    ns->offset += delta;
    ns->len -= delta;
 
+   if (s->filename != NULL)
+      ns->filename = VG_(arena_strdup)(VG_AR_CORE, s->filename);
+
    if (ns->symtab != NULL)
       VG_(symtab_incref)(ns->symtab);
 
@@ -156,17 +159,19 @@
 {
    Segment *s;
    Segment *next;
-   static const Bool debug = False || mem_debug;
-   Addr end = addr+len;
+   static const Bool debug = True || mem_debug;
+   Addr end;
 
    if (len == 0)
       return;
 
+   len = PGROUNDUP(len);
+   vg_assert(addr == PGROUNDDN(addr));
+
    if (debug)
       VG_(printf)("unmap_range(%p, %d)\n", addr, len);
 
-   len = PGROUNDUP(addr+len)-PGROUNDDN(addr);
-   addr = PGROUNDDN(addr);
+   end = addr+len;
 
    /* Everything must be page-aligned */
    vg_assert((addr & (VKI_BYTES_PER_PAGE-1)) == 0);
@@ -182,7 +187,7 @@
 
       if (debug)
 	 VG_(printf)("unmap: addr=%p-%p s=%p ->addr=%p-%p len=%d\n",
-		     addr, addr+len, s, s->addr, s->addr+s->len, s->len);
+		     addr, end, s, s->addr, seg_end, s->len);
 
       if (!VG_(seg_overlaps)(s, addr, len)) {
 	 if (debug)
@@ -217,12 +222,14 @@
 	 */
 	 Int delta = (addr+len) - s->addr;
 
+	 if (debug)
+	    VG_(printf)("  case 3: s->addr=%p s->len=%d delta=%d\n", s->addr, s->len, delta);
+
 	 s->addr += delta;
 	 s->offset += delta;
 	 s->len -= delta;
 
-	 if (debug)
-	    VG_(printf)("  case 3: s->addr=%p s->len=%d delta=%d\n", s->addr, s->len, delta);
+	 vg_assert(s->len != 0);
       } else if (addr > s->addr && end < seg_end) {
 	 /* [addr, addr+len) is contained within a single segment
 	    -> split segment into 3, delete middle portion
@@ -245,8 +252,8 @@
    }
 }
 
-/* If possible, merge segment with its neighbours - some segments,
-   including s, may be destroyed in the process */
+/* Return true if two segments are adjacent and mergable (s1 is
+   assumed to have a lower ->addr than s2) */
 static inline Bool neighbours(Segment *s1, Segment *s2)
 {
    if (s1->addr+s1->len != s2->addr)
@@ -273,8 +280,8 @@
    return True;
 }
 
-/* Merge segments in the address range if they're adjacent and
-   compatible */
+/* If possible, merge segment with its neighbours - some segments,
+   including s, may be destroyed in the process */
 static void merge_segments(Addr a, UInt len)
 {
    Segment *s;
diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c
index bb0c847..a6e6bc9 100644
--- a/coregrind/vg_symtab2.c
+++ b/coregrind/vg_symtab2.c
@@ -1208,8 +1208,7 @@
    si->start    = seg->addr;
    si->size     = seg->len;
    si->foffset  = seg->offset;
-   si->filename = VG_(arena_malloc)(VG_AR_SYMTAB, 1 + VG_(strlen)(seg->filename));
-   VG_(strcpy)(si->filename, seg->filename);
+   si->filename = VG_(arena_strdup)(VG_AR_SYMTAB, seg->filename);
 
    si->ref = 1;