Skip to content

Commit

Permalink
Merge pull request #463 from Rob--W/issue-130-dlsym
Browse files Browse the repository at this point in the history
Add FAKETIME_IGNORE_SYMBOLS to skip unneeded dlsym
  • Loading branch information
wolfcw authored Mar 19, 2024
2 parents b716122 + c745ab7 commit a3e9160
Showing 1 changed file with 58 additions and 0 deletions.
58 changes: 58 additions & 0 deletions src/libfaketime.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ static int initialized = 0;
static int fake_gettimeofday(struct timeval *tv);
static int fake_clock_gettime(clockid_t clk_id, struct timespec *tp);
int read_config_file();
bool str_array_contains(const char *haystack, const char *needle);
void *ft_dlvsym(void *handle, const char *symbol, const char *version, const char *full_name, char *ignore_list, bool should_debug_dlsym);

/** Semaphore protecting shared data */
static sem_t *shared_sem = NULL;
Expand Down Expand Up @@ -2640,6 +2642,11 @@ static void ftpl_really_init(void)
const char *progname = __progname;
#endif

char *ignore_list = getenv("FAKETIME_IGNORE_SYMBOLS");
bool should_debug_dlsym = getenv("FAKETIME_DEBUG_DLSYM");
#define dlsym(handle, symbol) ft_dlvsym(handle, symbol, NULL, symbol, ignore_list, should_debug_dlsym)
#define dlvsym(handle, symbol, version) ft_dlvsym(handle, symbol, version, symbol "@" version, ignore_list, should_debug_dlsym)

/* Look up all real_* functions. NULL will mark missing ones. */
real_stat = dlsym(RTLD_NEXT, "stat");
real_lstat = dlsym(RTLD_NEXT, "lstat");
Expand Down Expand Up @@ -2785,6 +2792,8 @@ static void ftpl_really_init(void)
do_macos_dyld_interpose();
#endif

#undef dlsym
#undef dlvsym
initialized = 1;

#ifdef FAKE_STATELESS
Expand Down Expand Up @@ -3042,6 +3051,38 @@ inline static void ftpl_init(void) {
}
}

void *ft_dlvsym(void *handle, const char *symbol, const char *version,
const char *full_name, char *ignore_list, bool should_debug_dlsym)
{
// dlsym or dlvsym with a non-resolving symbol results in a malloc call,
// which can trigger infinite recursion or deadlock, as seen in
// https://github.com/wolfcw/libfaketime/issues/130
// As a work-around, enable users to identify the list of calls,
// FAKETIME_DEBUG_DLSYM=1 faketime ...
// and then repeat the faketime call again to skip dlsym/dlvsym calls
// for these symbols, for example:
// FAKETIME_IGNORE_SYMBOLS=__ftime,timer_settime@GLIBC_2.2,timer_gettime@GLIBC_2.2 faketime ...
if (ignore_list && str_array_contains(ignore_list, full_name)) {
return NULL;
}
void *addr = NULL;
#ifdef __GLIBC__
if (version) {
addr = dlvsym(handle, symbol, version);
} else {
addr = dlsym(handle, symbol);
}
#else
// dlvsym does not exists, version is always NULL at compile time.
addr = dlsym(handle, symbol);
#endif
if (!addr && should_debug_dlsym) {
fprintf(stderr, "[FAKETIME_DEBUG_DLSYM] Cannot find symbol: %s\n", full_name);
}
return addr;
}


/*
* =======================================================================
* Helper functions === HELPER
Expand Down Expand Up @@ -3084,6 +3125,23 @@ static void prepare_config_contents(char *contents)
*write_position = '\0';
}

bool str_array_contains(const char *haystack, const char *needle)
{
size_t needle_len = strlen(needle);
char *pos = strstr(haystack, needle);
while (pos) {
if (pos == haystack || *(pos - 1) == ',') {
char nextc = *(pos + needle_len);
if (nextc == '\0' || nextc == ',') {
// Found needle in comma-separated haystack.
return true;
}
}
pos = strstr(pos + 1, needle);
}
return false;
}


/*
* =======================================================================
Expand Down

0 comments on commit a3e9160

Please sign in to comment.