mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-28 02:56:36 -04:00
e02b7b3455
Audit fixes for the async shard-publication pipeline (45a2dda):
- autocompile_shutdown(): stops the pipeline, kills the compiler tree via a
kill-on-close job object (assigned while the child is SUSPENDED so cmd.exe
cannot spawn grandchildren outside it), and JOINS the watcher + preparer —
never abandoning a thread inside the Windows loader lock at ExitProcess.
Wired first into shutdown_runtime(). Crash exits reap the tree via the job.
- Failed off-thread prepares retry (3 attempts, 100 ms) on the worker before
the artifact silently reverts to a synchronous emu-thread first-map; retry
and giveup counters exposed in autocompile_status_json.
- Capacity caps fail closed and LOUD: cand_register shouts once at CAND_CAP;
load_one_dll_prepared refuses at MAX_LOADED_DLLS before registering, so
dll_already_loaded can never lose track and double-register on rescan.
- Publication confinement is filesystem-resolved: published_path_valid
canonicalizes the cache root and the pipe path (GetFinalPathNameByHandle /
realpath), prefix-checks canonical forms, and the worker maps the canonical
string while holding a no-delete-share guard handle (TOCTOU). `..`/junction
spellings that passed the lexical check are now rejected — proven by the
new overlay_path_canon_test boundary test.
- test_autocompile_publication gains a shutdown-mid-run scenario asserting
prepared == committed + discarded with nothing queued; perf guards updated
to require validate -> guard-handle -> canonical first-map ordering.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
72 lines
2.3 KiB
C
72 lines
2.3 KiB
C
/* overlay_path_canon.c — see header. Windows resolves via
|
|
* GetFinalPathNameByHandle (the loader's own view of the object); POSIX via
|
|
* realpath. No allocation, no logging: callers decide how loud a rejection
|
|
* is. */
|
|
#include "overlay_path_canon.h"
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef _WIN32
|
|
|
|
int overlay_path_canonicalize_handle(HANDLE h, char *out, size_t cap) {
|
|
if (h == NULL || h == INVALID_HANDLE_VALUE || !out || cap < 2) return 0;
|
|
char buf[1024];
|
|
DWORD n = GetFinalPathNameByHandleA(h, buf, (DWORD)sizeof(buf),
|
|
FILE_NAME_NORMALIZED |
|
|
VOLUME_NAME_DOS);
|
|
if (n == 0 || n >= sizeof(buf)) return 0;
|
|
/* Strip the \\?\ (or rewrite \\?\UNC\ to \\) prefix so the result
|
|
* compares against ordinary Win32 paths. */
|
|
const char *p = buf;
|
|
char unc[1024];
|
|
if (strncmp(buf, "\\\\?\\UNC\\", 8) == 0) {
|
|
unc[0] = '\\';
|
|
unc[1] = '\\';
|
|
strncpy(unc + 2, buf + 8, sizeof(unc) - 3);
|
|
unc[sizeof(unc) - 1] = '\0';
|
|
p = unc;
|
|
} else if (strncmp(buf, "\\\\?\\", 4) == 0) {
|
|
p = buf + 4;
|
|
}
|
|
size_t len = strlen(p);
|
|
if (len + 1 > cap) return 0;
|
|
memcpy(out, p, len + 1);
|
|
return 1;
|
|
}
|
|
|
|
int overlay_path_canonicalize(const char *path, char *out, size_t cap) {
|
|
if (!path || !path[0]) return 0;
|
|
/* dwDesiredAccess=0 opens for attribute access only (works even on
|
|
* read-locked files); BACKUP_SEMANTICS is required to open directories. */
|
|
HANDLE h = CreateFileA(path, 0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
|
|
NULL);
|
|
if (h == INVALID_HANDLE_VALUE) return 0;
|
|
int ok = overlay_path_canonicalize_handle(h, out, cap);
|
|
CloseHandle(h);
|
|
return ok;
|
|
}
|
|
|
|
#else /* POSIX */
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 4096
|
|
#endif
|
|
|
|
int overlay_path_canonicalize(const char *path, char *out, size_t cap) {
|
|
if (!path || !path[0] || !out || cap < 2) return 0;
|
|
char resolved[PATH_MAX];
|
|
if (!realpath(path, resolved)) return 0;
|
|
size_t len = strlen(resolved);
|
|
if (len + 1 > cap) return 0;
|
|
memcpy(out, resolved, len + 1);
|
|
return 1;
|
|
}
|
|
|
|
#endif
|