static void faulthandler_alarm(int signum) { PyThreadState *tstate; const char* errmsg; int ok; _Py_write_noraise(fault_alarm.fd, fault_alarm.header, fault_alarm.header_len); /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); errmsg = _Py_DumpTracebackThreads(fault_alarm.fd, fault_alarm.interp, tstate); ok = (errmsg == NULL); if (ok && fault_alarm.repeat) alarm(fault_alarm.timeout); else /* don't call Py_CLEAR() here because it may call _Py_Dealloc() which is not signal safe */ alarm(0); if (fault_alarm.exit) _exit(1); }
void _Py_DumpDecimal(int fd, unsigned long value) { /* maximum number of characters required for output of %lld or %p. We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, plus 1 for the null byte. 53/22 is an upper bound for log10(256). */ char buffer[1 + (sizeof(unsigned long)*53-1) / 22 + 1]; char *ptr, *end; end = &buffer[Py_ARRAY_LENGTH(buffer) - 1]; ptr = end; *ptr = '\0'; do { --ptr; assert(ptr >= buffer); *ptr = '0' + (value % 10); value /= 10; } while (value); _Py_write_noraise(fd, ptr, end - ptr); }
static void dump_hexadecimal(int fd, unsigned long value, Py_ssize_t width) { char buffer[sizeof(unsigned long) * 2 + 1], *ptr, *end; const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1; if (width > size) width = size; end = &buffer[size]; ptr = end; *ptr = '\0'; do { --ptr; assert(ptr >= buffer); *ptr = Py_hexdigits[value & 15]; value >>= 4; } while ((end - ptr) < width || value); _Py_write_noraise(fd, ptr, end - ptr); }
static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; int ok; #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) sigset_t set; /* we don't want to receive any signal */ sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_us, 0); if (st == PY_LOCK_ACQUIRED) { PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); _Py_write_noraise(thread.fd, thread.header, (int)thread.header_len); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, NULL); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.running); }
void _Py_DumpASCII(int fd, PyObject *text) { PyASCIIObject *ascii = (PyASCIIObject *)text; Py_ssize_t i, size; int truncated; int kind; void *data = NULL; wchar_t *wstr = NULL; Py_UCS4 ch; if (!PyUnicode_Check(text)) return; size = ascii->length; kind = ascii->state.kind; if (kind == PyUnicode_WCHAR_KIND) { wstr = ((PyASCIIObject *)text)->wstr; if (wstr == NULL) return; size = ((PyCompactUnicodeObject *)text)->wstr_length; } else if (ascii->state.compact) { if (ascii->state.ascii) data = ((PyASCIIObject*)text) + 1; else data = ((PyCompactUnicodeObject*)text) + 1; } else { data = ((PyUnicodeObject *)text)->data.any; if (data == NULL) return; } if (MAX_STRING_LENGTH < size) { size = MAX_STRING_LENGTH; truncated = 1; } else { truncated = 0; } for (i=0; i < size; i++) { if (kind != PyUnicode_WCHAR_KIND) ch = PyUnicode_READ(kind, data, i); else ch = wstr[i]; if (' ' <= ch && ch <= 126) { /* printable ASCII character */ char c = (char)ch; _Py_write_noraise(fd, &c, 1); } else if (ch <= 0xff) { PUTS(fd, "\\x"); _Py_DumpHexadecimal(fd, ch, 2); } else if (ch <= 0xffff) { PUTS(fd, "\\u"); _Py_DumpHexadecimal(fd, ch, 4); } else { PUTS(fd, "\\U"); _Py_DumpHexadecimal(fd, ch, 8); } } if (truncated) { PUTS(fd, "..."); } }
/* * This function is code executed in the child process immediately after fork * to set things up and call exec(). * * All of the code in this function must only use async-signal-safe functions, * listed at `man 7 signal` or * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. * * This restriction is documented at * http://www.opengroup.org/onlinepubs/009695399/functions/fork.html. */ static void child_exec(char *const exec_array[], char *const argv[], char *const envp[], const char *cwd, int p2cread, int p2cwrite, int c2pread, int c2pwrite, int errread, int errwrite, int errpipe_read, int errpipe_write, int close_fds, int restore_signals, int call_setsid, PyObject *py_fds_to_keep, PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { int i, saved_errno, reached_preexec = 0; PyObject *result; const char* err_msg = ""; /* Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1]; if (make_inheritable(py_fds_to_keep, errpipe_write) < 0) goto error; /* Close parent's pipe ends. */ if (p2cwrite != -1) POSIX_CALL(close(p2cwrite)); if (c2pread != -1) POSIX_CALL(close(c2pread)); if (errread != -1) POSIX_CALL(close(errread)); POSIX_CALL(close(errpipe_read)); /* When duping fds, if there arises a situation where one of the fds is either 0, 1 or 2, it is possible that it is overwritten (#12607). */ if (c2pwrite == 0) POSIX_CALL(c2pwrite = dup(c2pwrite)); if (errwrite == 0 || errwrite == 1) POSIX_CALL(errwrite = dup(errwrite)); /* Dup fds for child. dup2() removes the CLOEXEC flag but we must do it ourselves if dup2() would be a no-op (issue #10806). */ if (p2cread == 0) { if (_Py_set_inheritable(p2cread, 1, NULL) < 0) goto error; } else if (p2cread != -1) POSIX_CALL(dup2(p2cread, 0)); /* stdin */ if (c2pwrite == 1) { if (_Py_set_inheritable(c2pwrite, 1, NULL) < 0) goto error; } else if (c2pwrite != -1) POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */ if (errwrite == 2) { if (_Py_set_inheritable(errwrite, 1, NULL) < 0) goto error; } else if (errwrite != -1) POSIX_CALL(dup2(errwrite, 2)); /* stderr */ /* Close pipe fds. Make sure we don't close the same fd more than */ /* once, or standard fds. */ if (p2cread > 2) POSIX_CALL(close(p2cread)); if (c2pwrite > 2 && c2pwrite != p2cread) POSIX_CALL(close(c2pwrite)); if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2) POSIX_CALL(close(errwrite)); if (cwd) POSIX_CALL(chdir(cwd)); if (restore_signals) _Py_RestoreSignals(); #ifdef HAVE_SETSID if (call_setsid) POSIX_CALL(setsid()); #endif reached_preexec = 1; if (preexec_fn != Py_None && preexec_fn_args_tuple) { /* This is where the user has asked us to deadlock their program. */ result = PyObject_Call(preexec_fn, preexec_fn_args_tuple, NULL); if (result == NULL) { /* Stringifying the exception or traceback would involve * memory allocation and thus potential for deadlock. * We've already faced potential deadlock by calling back * into Python in the first place, so it probably doesn't * matter but we avoid it to minimize the possibility. */ err_msg = "Exception occurred in preexec_fn."; errno = 0; /* We don't want to report an OSError. */ goto error; } /* Py_DECREF(result); - We're about to exec so why bother? */ } /* close FDs after executing preexec_fn, which might open FDs */ if (close_fds) { /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */ _close_open_fds(3, py_fds_to_keep); } /* This loop matches the Lib/os.py _execvpe()'s PATH search when */ /* given the executable_list generated by Lib/subprocess.py. */ saved_errno = 0; for (i = 0; exec_array[i] != NULL; ++i) { const char *executable = exec_array[i]; if (envp) { execve(executable, argv, envp); } else { execv(executable, argv); } if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) { saved_errno = errno; } } /* Report the first exec error, not the last. */ if (saved_errno) errno = saved_errno; error: saved_errno = errno; /* Report the posix error to our parent process. */ /* We ignore all write() return values as the total size of our writes is less than PIPEBUF and we cannot do anything about an error anyways. Use _Py_write_noraise() to retry write() if it is interrupted by a signal (fails with EINTR). */ if (saved_errno) { char *cur; _Py_write_noraise(errpipe_write, "OSError:", 8); cur = hex_errno + sizeof(hex_errno); while (saved_errno != 0 && cur > hex_errno) { *--cur = Py_hexdigits[saved_errno % 16]; saved_errno /= 16; } _Py_write_noraise(errpipe_write, cur, hex_errno + sizeof(hex_errno) - cur); _Py_write_noraise(errpipe_write, ":", 1); if (!reached_preexec) { /* Indicate to the parent that the error happened before exec(). */ _Py_write_noraise(errpipe_write, "noexec", 6); } /* We can't call strerror(saved_errno). It is not async signal safe. * The parent process will look the error message up. */ } else { _Py_write_noraise(errpipe_write, "SubprocessError:0:", 18); _Py_write_noraise(errpipe_write, err_msg, strlen(err_msg)); } }