diff options
Diffstat (limited to 'xorg-server/os')
-rw-r--r-- | xorg-server/os/backtrace.c | 49 | ||||
-rw-r--r-- | xorg-server/os/log.c | 175 | ||||
-rw-r--r-- | xorg-server/os/osinit.c | 8 | ||||
-rw-r--r-- | xorg-server/os/utils.c | 46 |
4 files changed, 250 insertions, 28 deletions
diff --git a/xorg-server/os/backtrace.c b/xorg-server/os/backtrace.c index 81348f417..daac60cf6 100644 --- a/xorg-server/os/backtrace.c +++ b/xorg-server/os/backtrace.c @@ -45,29 +45,37 @@ xorg_backtrace(void) int size, i; Dl_info info; - ErrorF("\n"); - ErrorF("Backtrace:\n"); + ErrorFSigSafe("\n"); + ErrorFSigSafe("Backtrace:\n"); size = backtrace(array, 64); for (i = 0; i < size; i++) { int rc = dladdr(array[i], &info); if (rc == 0) { - ErrorF("%d: ?? [%p]\n", i, array[i]); + ErrorFSigSafe("%u: ?? [%p]\n", i, array[i]); continue; } mod = (info.dli_fname && *info.dli_fname) ? info.dli_fname : "(vdso)"; if (info.dli_saddr) - ErrorF("%d: %s (%s+0x%lx) [%p]\n", i, mod, - info.dli_sname, - (long unsigned int) ((char *) array[i] - - (char *) info.dli_saddr), array[i]); + ErrorFSigSafe( + "%u: %s (%s+0x%x) [%p]\n", + i, + mod, + info.dli_sname, + (unsigned int)((char *) array[i] - + (char *) info.dli_saddr), + array[i]); else - ErrorF("%d: %s (%p+0x%lx) [%p]\n", i, mod, - info.dli_fbase, - (long unsigned int) ((char *) array[i] - - (char *) info.dli_fbase), array[i]); + ErrorFSigSafe( + "%u: %s (%p+0x%x) [%p]\n", + i, + mod, + info.dli_fbase, + (unsigned int)((char *) array[i] - + (char *) info.dli_fbase), + array[i]); } - ErrorF("\n"); + ErrorFSigSafe("\n"); } #else /* not glibc or glibc < 2.1 */ @@ -105,7 +113,7 @@ xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) strcpy(signame, "unknown"); } - ErrorF("** Signal %d (%s)\n", signo, signame); + ErrorFSigSafe("** Signal %u (%s)\n", signo, signame); } snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc); @@ -123,7 +131,8 @@ xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) symname = "<section start>"; offset = pc - (uintptr_t) dlinfo.dli_fbase; } - ErrorF("%s: %s:%s+0x%lx\n", header, dlinfo.dli_fname, symname, offset); + ErrorFSigSafe("%s: %s:%s+0x%x\n", header, dlinfo.dli_fname, symname, + offset); } else { @@ -131,7 +140,7 @@ xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) * probably poke elfloader here, but haven't written that code yet, * so we just print the pc. */ - ErrorF("%s\n", header); + ErrorFSigSafe("%s\n", header); } return 0; @@ -183,7 +192,7 @@ xorg_backtrace_pstack(void) if (bytesread > 0) { btline[bytesread] = 0; - ErrorF("%s", btline); + ErrorFSigSafe("%s", btline); } else if ((bytesread < 0) || ((errno != EINTR) && (errno != EAGAIN))) done = 1; @@ -203,8 +212,8 @@ void xorg_backtrace(void) { - ErrorF("\n"); - ErrorF("Backtrace:\n"); + ErrorFSigSafe("\n"); + ErrorFSigSafe("Backtrace:\n"); #ifdef HAVE_PSTACK /* First try fork/exec of pstack - otherwise fall back to walkcontext @@ -221,9 +230,9 @@ xorg_backtrace(void) walkcontext(&u, xorg_backtrace_frame, &depth); else #endif - ErrorF("Failed to get backtrace info: %s\n", strerror(errno)); + ErrorFSigSafe("Failed to get backtrace info: %s\n", strerror(errno)); } - ErrorF("\n"); + ErrorFSigSafe("\n"); } #else diff --git a/xorg-server/os/log.c b/xorg-server/os/log.c index 2c13c1a7d..25da9f63a 100644 --- a/xorg-server/os/log.c +++ b/xorg-server/os/log.c @@ -108,6 +108,7 @@ void (*OsVendorVErrorFProc) (const char *, va_list args) = NULL; #endif static FILE *logFile = NULL; +static int logFileFd = -1; static Bool logFlush = FALSE; static Bool logSync = FALSE; static int logVerbosity = DEFAULT_LOG_VERBOSITY; @@ -171,6 +172,14 @@ asm(".desc ___crashreporter_info__, 0x10"); #define X_NONE_STRING "" #endif +static size_t +strlen_sigsafe(const char *s) +{ + size_t len; + for (len = 0; s[len]; len++); + return len; +} + /* * LogInit is called to start logging to a file. It is also called (with * NULL arguments) when logging to a file is not wanted. It must always be @@ -211,6 +220,8 @@ LogInit(const char *fname, const char *backup) FatalError("Cannot open log file \"%s\"\n", logFileName); setvbuf(logFile, NULL, _IONBF, 0); + logFileFd = fileno(logFile); + /* Flush saved log information. */ if (saveBuffer && bufferSize > 0) { fwrite(saveBuffer, bufferPos, 1, logFile); @@ -243,6 +254,7 @@ LogClose(enum ExitCode error) (error == EXIT_NO_ERROR) ? "successfully" : "with error", error); fclose(logFile); logFile = NULL; + logFileFd = -1; } } @@ -267,16 +279,97 @@ LogSetParameter(LogParameter param, int value) } } -/* This function does the actual log message writes. */ +static int +pnprintf(char *string, size_t size, const char *f, va_list args) +{ + int f_idx = 0; + int s_idx = 0; + int f_len = strlen_sigsafe(f); + char *string_arg; + char number[21]; + int p_len; + int i; + uint64_t ui; + + for (; f_idx < f_len && s_idx < size - 1; f_idx++) { + if (f[f_idx] != '%') { + string[s_idx++] = f[f_idx]; + continue; + } + + switch (f[++f_idx]) { + case 's': + string_arg = va_arg(args, char*); + p_len = strlen_sigsafe(string_arg); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = string_arg[i]; + break; + + case 'u': + ui = va_arg(args, unsigned); + FormatUInt64(ui, number); + p_len = strlen_sigsafe(number); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = number[i]; + break; + + case 'p': + string[s_idx++] = '0'; + if (s_idx < size - 1) + string[s_idx++] = 'x'; + ui = (uintptr_t)va_arg(args, void*); + FormatUInt64Hex(ui, number); + p_len = strlen_sigsafe(number); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = number[i]; + break; + + case 'x': + ui = va_arg(args, unsigned); + FormatUInt64Hex(ui, number); + p_len = strlen_sigsafe(number); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = number[i]; + break; + + default: + va_arg(args, char*); + string[s_idx++] = '%'; + if (s_idx < size - 1) + string[s_idx++] = f[f_idx]; + break; + } + } + + string[s_idx] = '\0'; + + return s_idx; +} + +/* This function does the actual log message writes. It must be signal safe. + * When attempting to call non-signal-safe functions, guard them with a check + * of the inSignalContext global variable. */ static void LogSWrite(int verb, const char *buf, size_t len, Bool end_line) { static Bool newline = TRUE; if (verb < 0 || logVerbosity >= verb) - fwrite(buf, len, 1, stderr); + write(2, buf, len); + if (verb < 0 || logFileVerbosity >= verb) { - if (logFile) { + if (inSignalContext && logFileFd >= 0) { + write(logFileFd, buf, len); +#ifdef WIN32 + if (logFlush && logSync) + fsync(logFileFd); +#endif + } + else if (!inSignalContext && logFile) { if (newline) fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0); newline = end_line; @@ -289,7 +382,7 @@ LogSWrite(int verb, const char *buf, size_t len, Bool end_line) #endif } } - else if (needBuffer) { + else if (!inSignalContext && needBuffer) { if (len > bufferUnused) { bufferSize += 1024; bufferUnused += 1024; @@ -370,6 +463,16 @@ LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) Bool newline; size_t len = 0; + if (inSignalContext) { + BUG_WARN_MSG(inSignalContext, + "Warning: attempting to log data in a signal unsafe " + "manner while in signal context. Please update to check " + "inSignalContext and/or use LogMessageVerbSigSafe() or " + "ErrorFSigSafe(). The offending log format message is:\n" + "%s\n", format); + return; + } + type_str = LogMessageTypeVerbString(type, verb); if (!type_str) return; @@ -411,6 +514,44 @@ LogMessage(MessageType type, const char *format, ...) va_end(ap); } +/* Log a message using only signal safe functions. */ +void +LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + LogVMessageVerbSigSafe(type, verb, format, ap); + va_end(ap); +} + +void +LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args) +{ + const char *type_str; + char buf[1024]; + int len; + Bool newline; + + type_str = LogMessageTypeVerbString(type, verb); + if (!type_str) + return; + + /* if type_str is not "", prepend it and ' ', to message */ + if (type_str[0] != '\0') { + LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE); + LogSWrite(verb, " ", 1, FALSE); + } + + len = pnprintf(buf, sizeof(buf), format, args); + + /* Force '\n' at end of truncated line */ + if (sizeof(buf) - len == 1) + buf[len - 1] = '\n'; + + newline = (buf[len - 1] == '\n'); + LogSWrite(verb, buf, len, newline); +} + void LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format, va_list msg_args, const char *hdr_format, va_list hdr_args) @@ -421,6 +562,16 @@ LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format, Bool newline; size_t len = 0; + if (inSignalContext) { + BUG_WARN_MSG(inSignalContext, + "Warning: attempting to log data in a signal unsafe " + "manner while in signal context. Please update to check " + "inSignalContext and/or use LogMessageVerbSigSafe(). The " + "offending header and log message formats are:\n%s %s\n", + hdr_format, msg_format); + return; + } + type_str = LogMessageTypeVerbString(type, verb); if (!type_str) return; @@ -649,6 +800,22 @@ ErrorF(const char *f, ...) } void +VErrorFSigSafe(const char *f, va_list args) +{ + LogVMessageVerbSigSafe(X_ERROR, -1, f, args); +} + +void +ErrorFSigSafe(const char *f, ...) +{ + va_list args; + + va_start(args, f); + VErrorFSigSafe(f, args); + va_end(args); +} + +void LogPrintMarkers(void) { /* Show what the message marker symbols mean. */ diff --git a/xorg-server/os/osinit.c b/xorg-server/os/osinit.c index e2a220886..6cc040178 100644 --- a/xorg-server/os/osinit.c +++ b/xorg-server/os/osinit.c @@ -113,7 +113,7 @@ OsSigHandler(int signo) const char *dlerr = dlerror(); if (dlerr) { - LogMessage(X_ERROR, "Dynamic loader error: %s\n", dlerr); + LogMessageVerbSigSafe(X_ERROR, 1, "Dynamic loader error: %s\n", dlerr); } #endif /* RTLD_DI_SETSIGNAL */ @@ -129,8 +129,8 @@ OsSigHandler(int signo) #ifdef SA_SIGINFO if (sip->si_code == SI_USER) { - ErrorF("Recieved signal %d sent by process %ld, uid %ld\n", - signo, (long) sip->si_pid, (long) sip->si_uid); + ErrorFSigSafe("Recieved signal %u sent by process %u, uid %u\n", signo, + sip->si_pid, sip->si_uid); } else { switch (signo) { @@ -138,7 +138,7 @@ OsSigHandler(int signo) case SIGBUS: case SIGILL: case SIGFPE: - ErrorF("%s at address %p\n", strsignal(signo), sip->si_addr); + ErrorFSigSafe("%s at address %p\n", strsignal(signo), sip->si_addr); } } #endif diff --git a/xorg-server/os/utils.c b/xorg-server/os/utils.c index 3a1ef9303..998c3ed4a 100644 --- a/xorg-server/os/utils.c +++ b/xorg-server/os/utils.c @@ -204,6 +204,8 @@ int auditTrailLevel = 1; char *SeatId = NULL; +sig_atomic_t inSignalContext = FALSE; + #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) #define HAS_SAVED_IDS_AND_SETEUID #endif @@ -1791,3 +1793,47 @@ xstrtokenize(const char *str, const char *separators) free(list); return NULL; } + +/* Format a number into a string in a signal safe manner. The string should be + * at least 21 characters in order to handle all uint64_t values. */ +void +FormatUInt64(uint64_t num, char *string) +{ + uint64_t divisor; + int len; + int i; + + for (len = 1, divisor = 10; + len < 20 && num / divisor; + len++, divisor *= 10); + + for (i = len, divisor = 1; i > 0; i--, divisor *= 10) + string[i - 1] = '0' + ((num / divisor) % 10); + + string[len] = '\0'; +} + +/* Format a number into a hexadecimal string in a signal safe manner. The string + * should be at least 17 characters in order to handle all uint64_t values. */ +void +FormatUInt64Hex(uint64_t num, char *string) +{ + uint64_t divisor; + int len; + int i; + + for (len = 1, divisor = 0x10; + len < 16 && num / divisor; + len++, divisor *= 0x10); + + for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { + int val = (num / divisor) % 0x10; + + if (val < 10) + string[i - 1] = '0' + val; + else + string[i - 1] = 'a' + val - 10; + } + + string[len] = '\0'; +} |