ld.so in -current isn't building right now, due to an undefined reference to
_dl_realloc caused by the recent addition of _dl_reallocarray. The following
diff implements _dl_realloc, largely copied from the implementation in
lib/libc/stdlib/malloc.c.

tested on amd64

Index: malloc.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/malloc.c,v
retrieving revision 1.1
diff -u -b -w -p -r1.1 malloc.c
--- malloc.c    5 Jun 2014 08:39:07 -0000       1.1
+++ malloc.c    24 Jun 2014 08:24:43 -0000
@@ -78,6 +78,12 @@
 #define MMAP(sz)       _dl_mmap(NULL, (size_t)(sz), PROT_READ | PROT_WRITE, \
     MAP_ANON | MAP_PRIVATE, -1, (off_t) 0)
 
+#define MMAPA(a,sz)    _dl_mmap((a), (size_t)(sz), PROT_READ | PROT_WRITE, \
+    MAP_ANON | MAP_PRIVATE, -1, (off_t) 0)
+
+#define MQUERY(a, sz)  _dl_mquery((a), (size_t)(sz), PROT_READ | PROT_WRITE, \
+    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t)0)
+
 #define MMAP_ERROR(p)  (_dl_mmap_error(p) ? MAP_FAILED : (p))
 
 struct region_info {
@@ -277,6 +283,26 @@ unmap(struct dir_info *d, void *p, size_
                wrterror("malloc cache overflow");
 }
 
+static void
+zapcacheregion(struct dir_info *d, void *p, size_t len)
+{
+       u_int i;
+       struct region_info *r;
+       size_t rsz;
+
+       for (i = 0; i < mopts.malloc_cache; i++) {
+               r = &d->free_regions[i];
+               if (r->p >= p && r->p <= (void *)((char *)p + len)) {
+                       rsz = r->size << MALLOC_PAGESHIFT;
+                       if (_dl_munmap(r->p, rsz))
+                               wrterror("munmap");
+                       r->p = NULL;
+                       d->free_regions_size -= r->size;
+                       r->size = 0;
+               }
+       }
+}
+
 static void *
 map(struct dir_info *d, size_t sz, int zero_fill)
 {
@@ -987,6 +1013,119 @@ _dl_free(void *ptr)
        malloc_active--;
 }
 
+static void *
+orealloc(void *p, size_t newsz)
+{
+       struct region_info *r;
+       size_t oldsz, goldsz, gnewsz;
+       void *q;
+
+       if (p == NULL)
+               return omalloc(newsz, 0);
+
+       r = find(g_pool, p);
+       if (r == NULL) {
+               wrterror("bogus pointer (double free?)");
+               return NULL;
+       }
+       if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE)
+               return NULL;
+
+       REALSIZE(oldsz, r);
+       goldsz = oldsz;
+       if (oldsz > MALLOC_MAXCHUNK) {
+               if (oldsz < mopts.malloc_guard)
+                       wrterror("guard size");
+               oldsz -= mopts.malloc_guard;
+       }
+
+       gnewsz = newsz;
+       if (gnewsz > MALLOC_MAXCHUNK)
+               gnewsz += mopts.malloc_guard;
+
+       if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p) {
+               size_t roldsz = PAGEROUND(goldsz);
+               size_t rnewsz = PAGEROUND(gnewsz);
+
+               if (rnewsz > roldsz) {
+                       if (!mopts.malloc_guard) {
+                               void *hint = (char *)p + roldsz;
+                               size_t needed = rnewsz - roldsz;
+
+                               zapcacheregion(g_pool, hint, needed);
+                               q = MQUERY(hint, needed);
+                               if (q == hint)
+                                       q = MMAPA(hint, needed);
+                               else
+                                       q = MAP_FAILED;
+                               if (q == hint) {
+                                       if (mopts.malloc_junk == 2)
+                                               _dl_memset(q, SOME_JUNK, 
needed);
+                                       r->size = newsz;
+                                       return p;
+                               } else if (q != MAP_FAILED) {
+                                       if (_dl_munmap(q, needed))
+                                               wrterror("munmap");
+                               }
+                       }
+               } else if (rnewsz < roldsz) {
+                       if (mopts.malloc_guard) {
+                               if (_dl_mprotect((char *)p + roldsz -
+                                   mopts.malloc_guard, mopts.malloc_guard,
+                                   PROT_READ | PROT_WRITE))
+                                       wrterror("mprotect");
+                               if (_dl_mprotect((char *)p + rnewsz -
+                                   mopts.malloc_guard, mopts.malloc_guard,
+                                   PROT_NONE))
+                                       wrterror("mprotect");
+                       }
+                       unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz);
+                       r->size = gnewsz;
+                       return p;
+               } else {
+                       if (newsz > oldsz && mopts.malloc_junk == 2)
+                               _dl_memset((char *)p + newsz, SOME_JUNK,
+                                   rnewsz - mopts.malloc_guard - newsz);
+                       r->size = gnewsz;
+                       return p;
+               }
+       }
+       if (newsz <= oldsz && newsz > oldsz / 2) {
+               if (mopts.malloc_junk == 2 && newsz > 0)
+                       _dl_memset((char *)p + newsz, SOME_JUNK, oldsz - newsz);
+               return p;
+       } else if (newsz != oldsz) {
+               q = omalloc(newsz, 0);
+               if (q == NULL)
+                       return NULL;
+               if (newsz != 0 && oldsz != 0)
+                       _dl_bcopy(q, p, oldsz < newsz ? oldsz : newsz);
+               ofree(p);
+               return q;
+       } else {
+               return p;
+       }
+}
+
+void *
+_dl_realloc(void *ptr, size_t size)
+{
+       void *r;
+
+       malloc_func = "realloc():";
+       if (g_pool == NULL) {
+               if (malloc_init() != 0)
+                       return NULL;
+       }
+       if (malloc_active++) {
+               malloc_recurse();
+               return NULL;
+       }
+       r = orealloc(ptr, size);
+
+       malloc_active--;
+       return r;
+}
 
 /*
  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
Index: amd64/archdep.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/amd64/archdep.h,v
retrieving revision 1.5
diff -u -b -w -p -r1.5 archdep.h
--- amd64/archdep.h     19 Jan 2014 10:25:45 -0000      1.5
+++ amd64/archdep.h     24 Jun 2014 08:24:43 -0000
@@ -50,6 +50,13 @@ _dl_mmap(void *addr, unsigned int len, u
                flags, fd, 0, offset));
 }
 
+static inline void *
+_dl_mquery(void *addr, unsigned int len, unsigned int prot,
+       unsigned int flags, int fd, off_t offset)
+{
+       return((void *)_dl__syscall((quad_t)SYS_mquery, addr, len, prot,
+               flags, fd, 0, offset));
+}
 
 static inline void
 RELOC_REL(Elf64_Rel *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v)

Reply via email to