X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=bin%2Foverride.c;h=ac9e14cddd5bf98be6ad55e8726dc007a53868fd;hb=c60652e38ac6afd74bd8225e9dae5406f13aaa4f;hp=964bc21d8794fce1db8eebe80ee58330ad885685;hpb=389dcfadc1a417abe9f5d9a07ac7c7ad524562ea;p=vlc diff --git a/bin/override.c b/bin/override.c index 964bc21d87..ac9e14cddd 100644 --- a/bin/override.c +++ b/bin/override.c @@ -23,16 +23,18 @@ #endif #include +#define MAX_ERRORS 5 void vlc_enable_override (void); -#if defined (__GNUC__) /* typeof and statement-expression */ \ +#if defined (__GNUC__) \ && (defined (__ELF__) && !defined (__sun__)) /* Solaris crashes on printf("%s", NULL); which is legal, but annoying. */ #include #include #include +#include #include #include #ifdef HAVE_EXECINFO_H @@ -55,32 +57,37 @@ void vlc_enable_override (void) pthread_atfork (NULL, NULL, vlc_reset_override); } -static void vlogbug (const char *level, const char *func, const char *fmt, - va_list ap) +static void vlogbug (unsigned *pc, const char *level, const char *func, + const char *fmt, va_list ap) { #ifdef HAVE_BACKTRACE - const size_t framec = 4; + const size_t framec = 5; void *framev[framec]; backtrace (framev, framec); #endif flockfile (stderr); - fprintf (stderr, "%s: call to %s(", level, func); - vfprintf (stderr, fmt, ap); - fputs (")\n", stderr); - fflush (stderr); + if (*pc < MAX_ERRORS) + { + (*pc)++; + fprintf (stderr, "%s: call to %s(", level, func); + vfprintf (stderr, fmt, ap); + fputs (")\n", stderr); + fflush (stderr); #ifdef HAVE_BACKTRACE - backtrace_symbols_fd (framev + 2, framec - 2, fileno (stderr)); + backtrace_symbols_fd (framev + 2, framec - 2, fileno (stderr)); #endif + } funlockfile (stderr); } -static void logbug (const char *level, const char *func, const char *fmt, ...) +static void logbug (unsigned *pc, const char *level, const char *func, + const char *fmt, ...) { va_list ap; va_start (ap, fmt); - vlogbug (level, func, fmt, ap); + vlogbug (pc, level, func, fmt, ap); va_end (ap); } @@ -96,9 +103,29 @@ static void *getsym (const char *name) return sym; } -#define LOG(level, ...) logbug(level, __func__, __VA_ARGS__) +#define LOG(level, ...) \ + do { \ + static unsigned counter = 0; \ + logbug(&counter, level, __func__, __VA_ARGS__); \ + } while (0) + +/* Evil non-standard GNU C macro ;) + * typeof keyword, + * statement-expression, + * nested function... + */ #define CALL(func, ...) \ - ({ typeof (func) *sym = getsym ( # func); sym (__VA_ARGS__); }) +({ \ + static typeof (func) *sym = NULL; \ + static pthread_once_t once = PTHREAD_ONCE_INIT; \ + auto void getsym_once (void); \ + void getsym_once (void) \ + { \ + sym = getsym ( # func); \ + } \ + pthread_once (&once, getsym_once); \ + sym (__VA_ARGS__); \ +}) /*** Environment *** @@ -148,53 +175,118 @@ int unsetenv (const char *name) * preserve reproducibility of the number sequence (which usually does not * matter). **/ -static pthread_mutex_t prng_lock = PTHREAD_MUTEX_INITIALIZER; +static struct +{ + pthread_mutex_t lock; + unsigned int seed; +} prng = { PTHREAD_MUTEX_INITIALIZER, 0, }; void srand (unsigned int seed) { - pthread_mutex_lock (&prng_lock); + pthread_mutex_lock (&prng.lock); LOG("Warning", "%d", seed); - CALL(srand, seed); - pthread_mutex_unlock (&prng_lock); + prng.seed = seed; + pthread_mutex_unlock (&prng.lock); } int rand (void) { int ret; - pthread_mutex_lock (&prng_lock); + pthread_mutex_lock (&prng.lock); LOG("Warning", ""); - ret = CALL(rand); - pthread_mutex_unlock (&prng_lock); + ret = rand_r (&prng.seed); + pthread_mutex_unlock (&prng.lock); return ret; } +#if 0 /** Signals **/ #include +static bool blocked_signal (int num) +{ + switch (num) + { + case SIGINT: + case SIGHUP: + case SIGQUIT: + case SIGTERM: + case SIGPIPE: + case SIGCHLD: + return true; + } + return false; +} + void (*signal (int signum, void (*handler) (int))) (int) { if (override) { - const char *msg = "Error"; - - if ((signum == SIGPIPE && handler == SIG_IGN) - || (signum != SIGPIPE && handler == SIG_DFL)) - /* Same settings we already use */ - msg = "Warning"; - LOG(msg, "%d, %p", signum, handler); + if (handler != SIG_IGN && handler != SIG_DFL) + goto error; + if (!blocked_signal (signum)) + goto error; + /* For our blocked signals, the handler won't matter much... */ + if (handler == SIG_DFL) + LOG("Warning", "%d, SIG_DFL", signum, handler); } return CALL(signal, signum, handler); +error: + LOG("Blocked", "%d, %p", signum, handler); + return SIG_DFL; } int sigaction (int signum, const struct sigaction *act, struct sigaction *old) { - if (act != NULL) - LOG("Error", "%d, %p, %p", signum, act, old); + if (override && act != NULL) + { + if ((act->sa_flags & SA_SIGINFO) + || (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL)) + goto error; + if (act->sa_handler == SIG_DFL) + LOG("Warning", "%d, %p, SIG_DFL", signum, act); + } return CALL(sigaction, signum, act, old); +error: + LOG("Blocked", "%d, %p, %p", signum, act, old); + return -1; } +#endif + +/*** Locales *** + * setlocale() is not thread-safe and has a tendency to crash other threads as + * quite many libc and libintl calls depend on the locale. + * Use uselocale() instead for thread-safety. + */ +#include + +char *setlocale (int cat, const char *locale) +{ + if (override && locale != NULL) + { + LOG("Blocked", "%d, \"%s\"", cat, locale); + return NULL; + } + return CALL(setlocale, cat, locale); +} + + +/* strerror() is not thread-safe in theory (POSIX), nor in practice (glibc). + * This caused quite nasty crashes in the history of VLC/Linux. */ +char *strerror (int val) +{ + if (override) + { + static const char msg[] = + "Error message unavailable (use strerror_r instead of strerror)!"; + LOG("Blocked", "%d", val); + return (char *)msg; + } + return CALL(strerror, val); +} /*** Xlib ****/ #ifdef HAVE_X11_XLIB_H