Reapply "feat: add unit buffer option"
This reverts commit 08da357e966727b96274f3442646734d7df1f6ea.
This commit is contained in:
@@ -77,6 +77,7 @@ async def run_pycdc_async(
|
||||
seq_file_path: str,
|
||||
path_for_log: str,
|
||||
*,
|
||||
unit_buf: bool = False,
|
||||
no_banner: bool = False,
|
||||
show_all: bool = False,
|
||||
show_err_opcode: bool = False,
|
||||
@@ -85,6 +86,8 @@ async def run_pycdc_async(
|
||||
logger = logging.getLogger("shot")
|
||||
try:
|
||||
options = []
|
||||
if unit_buf:
|
||||
options.append("--unitbuf")
|
||||
if no_banner:
|
||||
options.append("--no-banner")
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
@@ -103,6 +106,21 @@ async def run_pycdc_async(
|
||||
logger.warning(f"PYCDC: {line} ({path_for_log})")
|
||||
|
||||
for line in stderr_lines:
|
||||
if not unit_buf and line.startswith("Access violation caught"):
|
||||
# retry with --unitbuf
|
||||
await run_pycdc_async(
|
||||
exe_path,
|
||||
seq_file_path,
|
||||
path_for_log,
|
||||
unit_buf=True,
|
||||
no_banner=no_banner,
|
||||
show_all=show_all,
|
||||
show_err_opcode=show_err_opcode,
|
||||
show_warn_stack=show_warn_stack,
|
||||
)
|
||||
# do not log anything because it will be logged in the retried call
|
||||
return
|
||||
|
||||
if line.startswith(
|
||||
(
|
||||
"Warning: Stack history is empty",
|
||||
@@ -121,6 +139,7 @@ async def run_pycdc_async(
|
||||
"Unsupported argument",
|
||||
"Unsupported Node type",
|
||||
"Unsupported node type",
|
||||
"Access violation caught",
|
||||
)
|
||||
): # annoying wont-fix errors
|
||||
if show_all:
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
/** I want to use functions in pycdas.cpp directly, but not moving them to
|
||||
* another file, to sync with upstream in the future easily.
|
||||
*/
|
||||
@@ -9,10 +25,73 @@
|
||||
|
||||
const char* VERSION = "v0.2.1+";
|
||||
|
||||
#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
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* infile = nullptr;
|
||||
unsigned disasm_flags = 0;
|
||||
bool unitbuf = false;
|
||||
bool banner = true;
|
||||
std::ofstream dc_out_file;
|
||||
std::ofstream das_out_file;
|
||||
@@ -27,9 +106,12 @@ int main(int argc, char* argv[])
|
||||
fputs("Options:\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(" --no-banner Don't output banner\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 (strcmp(argv[arg], "--no-banner") == 0) {
|
||||
banner = false;
|
||||
} else if (argv[arg][0] == '-') {
|
||||
@@ -58,17 +140,51 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
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<native_handle_t, HANDLE>) {
|
||||
g_dc_h = dc_nh;
|
||||
g_das_h = das_nh;
|
||||
} else if constexpr (std::is_integral_v<native_handle_t>) {
|
||||
intptr_t dc_handle = _get_osfhandle(dc_nh);
|
||||
if (dc_handle != -1 && dc_handle != reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE)) {
|
||||
g_dc_h = reinterpret_cast<HANDLE>(dc_handle);
|
||||
}
|
||||
intptr_t das_handle = _get_osfhandle(das_nh);
|
||||
if (das_handle != -1 && das_handle != reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE)) {
|
||||
g_das_h = reinterpret_cast<HANDLE>(das_handle);
|
||||
}
|
||||
} else {
|
||||
// ignore, keep as INVALID_HANDLE_VALUE
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
PycModule mod;
|
||||
try {
|
||||
mod.loadFromOneshotSequenceFile(infile);
|
||||
|
||||
Reference in New Issue
Block a user