Page MenuHomeFreeBSD

D57908.diff
No OneTemporary

D57908.diff

diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -113,7 +113,7 @@
note_end = 0;
note_map = NULL;
note_map_len = 0;
- segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
+ segs = xcalloc(hdr->e_phnum, sizeof(segs[0]));
stack_flags = PF_X | PF_R | PF_W;
text_end = 0;
while (phdr < phlimit) {
@@ -351,6 +351,7 @@
if (!phdr_in_zero_page(hdr))
munmap(phdr, hdr->e_phnum * sizeof(phdr[0]));
munmap(hdr, page_size);
+ free(segs);
return (NULL);
}
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -319,6 +319,7 @@
*/
typedef struct Struct_DoneList {
const Obj_Entry **objs; /* Array of object pointers */
+ struct Struct_SymLook *req;
unsigned int num_alloc; /* Allocated size of the array */
unsigned int num_used; /* Number of array slots used */
} DoneList;
@@ -348,6 +349,7 @@
const Obj_Entry *defobj_out;
const Elf_Sym *sym_out;
struct Struct_RtldLockState *lockstate;
+ void *donelist_mem;
} SymLook;
enum {
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -342,16 +342,6 @@
static void (*rtld_exit_ptr)(void);
-/*
- * Fill in a DoneList with an allocation large enough to hold all of
- * the currently-loaded objects. Keep this as a macro since it calls
- * alloca and we want that to occur within the scope of the caller.
- */
-#define donelist_init(dlp) \
- ((dlp)->objs = alloca(obj_count * sizeof(dlp)->objs[0]), \
- assert((dlp)->objs != NULL), (dlp)->num_alloc = obj_count, \
- (dlp)->num_used = 0)
-
#define LD_UTRACE(e, h, mb, ms, r, n) \
do { \
if (ld_utrace != NULL) \
@@ -1042,6 +1032,38 @@
return ((func_ptr_type)obj_main->entry);
}
+/*
+ * Fill in a DoneList with an allocation large enough to hold all of
+ * the currently-loaded Keep this as a macro since it calls
+ * alloca and we want that to occur within the scope of the caller.
+ */
+#define DLP_ALLOCA_LIMIT 256
+#define donelist_init(_DLP, _REQ) do { \
+ DoneList *_dlp = _DLP; \
+ SymLook *_r = _REQ; \
+ _dlp->num_alloc = obj_count, \
+ _dlp->req = NULL; \
+ if (_dlp->num_alloc > DLP_ALLOCA_LIMIT) { \
+ _dlp->objs = xcalloc(_dlp->num_alloc, sizeof(_dlp->objs[0])); \
+ if (_r != NULL && _r->donelist_mem == NULL) { \
+ _r->donelist_mem = _dlp->objs; \
+ _dlp->req = _r; \
+ } \
+ } else { \
+ _dlp->objs = alloca(_dlp->num_alloc * sizeof(_dlp->objs[0])); \
+ } \
+ _dlp->num_used = 0; \
+} while (0)
+
+static void
+donelist_free(DoneList *dlp)
+{
+ if (dlp->num_alloc > DLP_ALLOCA_LIMIT)
+ free(dlp->objs);
+ if (dlp->req != NULL)
+ dlp->req->donelist_mem = NULL;
+}
+
void *
rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def)
{
@@ -2319,7 +2341,7 @@
if (root->dag_inited)
return;
- donelist_init(&donelist);
+ donelist_init(&donelist, NULL);
/* Root object belongs to own DAG. */
objlist_push_tail(&root->dldags, root);
@@ -2342,6 +2364,7 @@
}
}
root->dag_inited = true;
+ donelist_free(&donelist);
}
static void
@@ -4103,8 +4126,10 @@
LD_UTRACE(UTRACE_DLSYM_START, handle, NULL, 0, 0, name);
rlock_acquire(rtld_bind_lock, &lockstate);
- if (sigsetjmp(lockstate.env, 0) != 0)
+ if (sigsetjmp(lockstate.env, 0) != 0) {
lock_upgrade(rtld_bind_lock, &lockstate);
+ free(req.donelist_mem);
+ }
if (handle == NULL || handle == RTLD_NEXT || handle == RTLD_DEFAULT ||
handle == RTLD_SELF) {
if ((obj = obj_from_addr(retaddr)) == NULL) {
@@ -4173,7 +4198,7 @@
return (NULL);
}
- donelist_init(&donelist);
+ donelist_init(&donelist, &req);
if (obj->mainprog) {
/* Handle obtained by dlopen(NULL, ...) implies global
* scope. */
@@ -4204,6 +4229,7 @@
defobj = req.defobj_out;
}
}
+ donelist_free(&donelist);
}
if (def != NULL) {
@@ -4731,21 +4757,24 @@
{
SymLook req;
DoneList donelist;
+ const void **res;
symlook_init(&req, name);
req.lockstate = lockstate;
- donelist_init(&donelist);
+ donelist_init(&donelist, NULL);
if (symlook_global(&req, &donelist) != 0)
return (NULL);
if (ELF_ST_TYPE(req.sym_out->st_info) == STT_FUNC)
- return ((const void **)make_function_pointer(req.sym_out,
- req.defobj_out));
+ res = (const void **)make_function_pointer(req.sym_out,
+ req.defobj_out);
else if (ELF_ST_TYPE(req.sym_out->st_info) == STT_GNU_IFUNC)
- return ((const void **)rtld_resolve_ifunc(req.defobj_out,
- req.sym_out));
+ res = (const void **)rtld_resolve_ifunc(req.defobj_out,
+ req.sym_out);
else
- return ((const void **)(req.defobj_out->relocbase +
- req.sym_out->st_value));
+ res = (const void **)(req.defobj_out->relocbase +
+ req.sym_out->st_value);
+ donelist_free(&donelist);
+ return (res);
}
/*
@@ -4820,7 +4849,7 @@
SymLook req1;
int res;
- donelist_init(&donelist);
+ donelist_init(&donelist, req);
symlook_init_from_req(&req1, req);
/*
@@ -4873,6 +4902,7 @@
}
}
+ donelist_free(&donelist);
return (req->sym_out != NULL ? 0 : ESRCH);
}
@@ -4954,13 +4984,15 @@
Needed_Entry *needed)
{
DoneList donelist;
- int flags;
+ int flags, res;
flags = (req->flags & SYMLOOK_EARLY) != 0 ? RTLD_LO_EARLY : 0;
load_filtees(__DECONST(Obj_Entry *, obj), flags, req->lockstate);
- donelist_init(&donelist);
+ donelist_init(&donelist, NULL);
symlook_init_from_req(req1, req);
- return (symlook_needed(req1, needed, &donelist));
+ res = symlook_needed(req1, needed, &donelist);
+ donelist_free(&donelist);
+ return (res);
}
/*
@@ -6305,6 +6337,7 @@
dst->defobj_out = NULL;
dst->sym_out = NULL;
dst->lockstate = src->lockstate;
+ dst->donelist_mem = NULL;
}
static int
@@ -6878,31 +6911,6 @@
strlen(name))));
}
-/* malloc */
-void *
-malloc(size_t nbytes)
-{
- return (__crt_malloc(nbytes));
-}
-
-void *
-calloc(size_t num, size_t size)
-{
- return (__crt_calloc(num, size));
-}
-
-void
-free(void *cp)
-{
- __crt_free(cp);
-}
-
-void *
-realloc(void *cp, size_t nbytes)
-{
- return (__crt_realloc(cp, nbytes));
-}
-
extern int _rtld_version__FreeBSD_version __exported;
int _rtld_version__FreeBSD_version = __FreeBSD_version;
diff --git a/libexec/rtld-elf/xmalloc.c b/libexec/rtld-elf/xmalloc.c
--- a/libexec/rtld-elf/xmalloc.c
+++ b/libexec/rtld-elf/xmalloc.c
@@ -26,6 +26,8 @@
*/
#include <sys/param.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -35,12 +37,36 @@
#include "rtld_malloc.h"
#include "rtld_libc.h"
+static int rtld_malloc_spinlock;
+
+/*
+ * Almost always the rtld malloc is called under the write-locked rtld
+ * bind lock. Due to this, xlock() would need a single CAS to take
+ * the spinlock. But some places only own read-locked rtld bind lock,
+ * and then the spinlock protects the malloc structures from the
+ * parallel updates.
+ */
+static void
+xlock(void)
+{
+ while (atomic_cmpset_acq_int(&rtld_malloc_spinlock, 0, 1) == 0)
+ cpu_spinwait();
+}
+
+static void
+xunlock(void)
+{
+ atomic_store_rel_int(&rtld_malloc_spinlock, 0);
+}
+
void *
xcalloc(size_t number, size_t size)
{
void *p;
+ xlock();
p = __crt_calloc(number, size);
+ xunlock();
if (p == NULL) {
rtld_fdputstr(STDERR_FILENO, "Out of memory\n");
_exit(1);
@@ -51,10 +77,11 @@
void *
xmalloc(size_t size)
{
-
void *p;
+ xlock();
p = __crt_malloc(size);
+ xunlock();
if (p == NULL) {
rtld_fdputstr(STDERR_FILENO, "Out of memory\n");
_exit(1);
@@ -83,10 +110,53 @@
if (align < sizeof(void *))
align = sizeof(void *);
+ xlock();
res = __crt_aligned_alloc_offset(align, size, offset);
+ xunlock();
if (res == NULL) {
rtld_fdputstr(STDERR_FILENO, "Out of memory\n");
_exit(1);
}
return (res);
}
+
+void *
+malloc(size_t size)
+{
+ void *p;
+
+ xlock();
+ p = __crt_malloc(size);
+ xunlock();
+ return (p);
+}
+
+void *
+calloc(size_t num, size_t size)
+{
+ void *p;
+
+ xlock();
+ p = __crt_calloc(num, size);
+ xunlock();
+ return (p);
+}
+
+void
+free(void *cp)
+{
+ xlock();
+ __crt_free(cp);
+ xunlock();
+}
+
+void *
+realloc(void *cp, size_t nbytes)
+{
+ void *p;
+
+ xlock();
+ p = __crt_realloc(cp, nbytes);
+ xunlock();
+ return (p);
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Jun 28, 9:43 PM (8 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34443329
Default Alt Text
D57908.diff (8 KB)

Event Timeline