rtld: preserve the 'seen' state of the dlerror message in errmsg_save()
rtld preserves its current error message around calls to user init/fini
lists, to not override original error with potential secondary errors
caused by user code recursing into rtld. After 4d9128da54
,
the preservation of the string itself is not enough, the 'seen'
indicator must be preserved as well. Otherwise, since new code does not
clear string (it cannot), call to _rtld_error() from errmsg_restore()
revived whatever message was consumed last.
Change errmsg_save() to return structure recording both 'seen' indicator
and the message, if any.
PR: 255698
Reported by: Eugene M. Kim <astralblue@gmail.com>
Sponsored by: The FreeBSD Foundation
MFC after: 3 days
This commit is contained in:
parent
5e7cdf1817
commit
630caa95d4
@ -81,6 +81,10 @@ extern struct r_debug r_debug; /* For GDB */
|
||||
extern int _thread_autoinit_dummy_decl;
|
||||
extern void (*__cleanup)(void);
|
||||
|
||||
struct dlerror_save {
|
||||
int seen;
|
||||
char *msg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Function declarations.
|
||||
@ -100,8 +104,8 @@ static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj,
|
||||
static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int);
|
||||
static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *);
|
||||
static bool donelist_check(DoneList *, const Obj_Entry *);
|
||||
static void errmsg_restore(char *);
|
||||
static char *errmsg_save(void);
|
||||
static void errmsg_restore(struct dlerror_save *);
|
||||
static struct dlerror_save *errmsg_save(void);
|
||||
static void *fill_search_info(const char *, size_t, void *);
|
||||
static char *find_library(const char *, const Obj_Entry *, int *);
|
||||
static const char *gethints(bool);
|
||||
@ -941,10 +945,16 @@ _rtld_error(const char *fmt, ...)
|
||||
/*
|
||||
* Return a dynamically-allocated copy of the current error message, if any.
|
||||
*/
|
||||
static char *
|
||||
static struct dlerror_save *
|
||||
errmsg_save(void)
|
||||
{
|
||||
return (xstrdup(lockinfo.dlerror_loc()));
|
||||
struct dlerror_save *res;
|
||||
|
||||
res = xmalloc(sizeof(*res));
|
||||
res->seen = *lockinfo.dlerror_seen();
|
||||
if (res->seen == 0)
|
||||
res->msg = xstrdup(lockinfo.dlerror_loc());
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -952,14 +962,17 @@ errmsg_save(void)
|
||||
* by errmsg_save(). The copy is freed.
|
||||
*/
|
||||
static void
|
||||
errmsg_restore(char *saved_msg)
|
||||
errmsg_restore(struct dlerror_save *saved_msg)
|
||||
{
|
||||
if (saved_msg == NULL)
|
||||
_rtld_error("");
|
||||
else {
|
||||
_rtld_error("%s", saved_msg);
|
||||
free(saved_msg);
|
||||
if (saved_msg == NULL || saved_msg->seen == 1) {
|
||||
*lockinfo.dlerror_seen() = 1;
|
||||
} else {
|
||||
*lockinfo.dlerror_seen() = 0;
|
||||
strlcpy(lockinfo.dlerror_loc(), saved_msg->msg,
|
||||
lockinfo.dlerror_loc_sz);
|
||||
free(saved_msg->msg);
|
||||
}
|
||||
free(saved_msg);
|
||||
}
|
||||
|
||||
static const char *
|
||||
@ -2736,7 +2749,7 @@ static void
|
||||
objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate)
|
||||
{
|
||||
Objlist_Entry *elm;
|
||||
char *saved_msg;
|
||||
struct dlerror_save *saved_msg;
|
||||
Elf_Addr *fini_addr;
|
||||
int index;
|
||||
|
||||
@ -2812,7 +2825,7 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate)
|
||||
{
|
||||
Objlist_Entry *elm;
|
||||
Obj_Entry *obj;
|
||||
char *saved_msg;
|
||||
struct dlerror_save *saved_msg;
|
||||
Elf_Addr *init_addr;
|
||||
void (*reg)(void (*)(void));
|
||||
int index;
|
||||
|
Loading…
Reference in New Issue
Block a user