From 6c6aa159df0657104206d9e0f897e474903d9376 Mon Sep 17 00:00:00 2001 From: Lil-Ran Date: Wed, 19 Nov 2025 00:07:46 +0800 Subject: [PATCH] sync with 71c3307: unit buffer --- pycdas.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/pycdas.cpp b/pycdas.cpp index 3d0f6d6..180eb81 100644 --- a/pycdas.cpp +++ b/pycdas.cpp @@ -1,3 +1,19 @@ +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +#include +#endif + +#ifdef _WIN32 +#include +#include +#include +#endif + #include #include #include @@ -16,6 +32,68 @@ # define PATHSEP '/' #endif +#ifdef _WIN32 + +// Windows: Use SEH/UEF; prefer calling only Win32 APIs +#ifdef __cpp_lib_fstream_native_handle +static HANDLE g_dc_h = INVALID_HANDLE_VALUE; +static HANDLE g_das_h = INVALID_HANDLE_VALUE; +#endif + +static LONG WINAPI av_handler(EXCEPTION_POINTERS* /*ep*/) { + const char msg[] = "Access violation caught. Best-effort FlushFileBuffers.\n"; + DWORD wrote = 0; + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, sizeof(msg) - 1, &wrote, nullptr); +#ifdef __cpp_lib_fstream_native_handle + if (g_das_h != INVALID_HANDLE_VALUE) FlushFileBuffers(g_das_h); + if (g_dc_h != INVALID_HANDLE_VALUE) FlushFileBuffers(g_dc_h); +#endif + TerminateProcess(GetCurrentProcess(), 0xC0000005); + return EXCEPTION_EXECUTE_HANDLER; +} + +struct SehInstall { + SehInstall() { + // Suppress WER popups; let the UEF handle it directly + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + SetUnhandledExceptionFilter(av_handler); + } +} seh_install_guard; + +#else // !_WIN32 + +#ifdef __cpp_lib_fstream_native_handle +static int g_dc_fd = -1; +static int g_das_fd = -1; + +static void segv_handler(int sig) { + const char msg[] = "Access violation caught. Best-effort fsync.\n"; + // Only use async-signal-safe functions + write(STDERR_FILENO, msg, sizeof(msg)-1); + if (g_das_fd != -1) fsync(g_das_fd); + if (g_dc_fd != -1) fsync(g_dc_fd); + _Exit(128 + sig); +} +#else +static void segv_handler(int sig) { + const char msg[] = "Access violation caught.\n"; + write(STDERR_FILENO, msg, sizeof(msg)-1); + _Exit(128 + sig); +} +#endif + +struct SegvInstall { + SegvInstall() { + struct sigaction sa{}; + sa.sa_handler = segv_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGSEGV, &sa, nullptr); + } +} segv_install_guard; + +#endif // _WIN32 + static const char* flag_names[] = { "CO_OPTIMIZED", "CO_NEWLOCALS", "CO_VARARGS", "CO_VARKEYWORDS", "CO_NESTED", "CO_GENERATOR", "CO_NOFREE", "CO_COROUTINE", @@ -269,6 +347,7 @@ int main(int argc, char* argv[]) bool marshalled = false; const char* version = nullptr; unsigned disasm_flags = 0; + bool unitbuf = false; std::ofstream dc_out_file; std::ofstream das_out_file; @@ -301,8 +380,11 @@ int main(int argc, char* argv[]) fputs(" -v Specify a Python version for loading a compiled code object\n", stderr); fputs(" --pycode-extra Show extra fields in PyCode object dumps\n", stderr); fputs(" --show-caches Don't suprress CACHE instructions in Python 3.11+ disassembly\n", stderr); + fputs(" --unitbuf Set output streams to be unbuffered\n", stderr); fputs(" --help Show this help text and then exit\n", stderr); return 0; + } else if (strcmp(argv[arg], "--unitbuf") == 0) { + unitbuf = true; } else if (argv[arg][0] == '-') { fprintf(stderr, "Error: Unrecognized argument %s\n", argv[arg]); return 1; @@ -323,17 +405,51 @@ int main(int argc, char* argv[]) std::string prefix_name(outfile ? outfile : infile); dc_out_file.open(prefix_name + ".cdc.py", std::ios_base::out); + if (unitbuf) { + dc_out_file.setf(std::ios::unitbuf); + } if (dc_out_file.fail()) { fprintf(stderr, "Error opening file '%s' for writing\n", (prefix_name + ".cdc.py").c_str()); return 1; } das_out_file.open(prefix_name + ".das", std::ios_base::out); + if (unitbuf) { + das_out_file.setf(std::ios::unitbuf); + } if (das_out_file.fail()) { fprintf(stderr, "Error opening file '%s' for writing\n", (prefix_name + ".das").c_str()); return 1; } +#ifdef __cpp_lib_fstream_native_handle +#ifndef _WIN32 + g_dc_fd = dc_out_file.native_handle(); + g_das_fd = das_out_file.native_handle(); +#else + // Extract underlying handles to flush on exceptions + // MSVC's native_handle is typically a HANDLE; MinGW may return a fd, requiring conversion via _get_osfhandle + auto dc_nh = dc_out_file.native_handle(); + auto das_nh = das_out_file.native_handle(); + using native_handle_t = decltype(dc_nh); + if constexpr (std::is_same_v) { + g_dc_h = dc_nh; + g_das_h = das_nh; + } else if constexpr (std::is_integral_v) { + intptr_t dc_handle = _get_osfhandle(dc_nh); + if (dc_handle != -1 && dc_handle != reinterpret_cast(INVALID_HANDLE_VALUE)) { + g_dc_h = reinterpret_cast(dc_handle); + } + intptr_t das_handle = _get_osfhandle(das_nh); + if (das_handle != -1 && das_handle != reinterpret_cast(INVALID_HANDLE_VALUE)) { + g_das_h = reinterpret_cast(das_handle); + } + } else { + // ignore, keep as INVALID_HANDLE_VALUE + } +#endif +#endif + PycModule mod; if (!marshalled) { try {