Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160790556
D57908.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D57908.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D57908: rtld: stop using alloca()
Attached
Detach File
Event Timeline
Log In to Comment