mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Overlay autocompile: compiler scratch files beside the overlay cache (#714)
This commit is contained in:
committed by
GitHub
parent
5c07d42f6a
commit
0d1389e7d3
@@ -1516,6 +1516,10 @@ if(BUILD_TESTING)
|
||||
add_test(NAME mod_resident_test COMMAND mod_resident_test)
|
||||
|
||||
if(WIN32)
|
||||
add_executable(autocompile_child_env_test tests/test_autocompile_child_env.c)
|
||||
target_include_directories(autocompile_child_env_test PRIVATE src)
|
||||
add_test(NAME autocompile_child_env_test COMMAND autocompile_child_env_test)
|
||||
|
||||
add_executable(autocompile_publication_test
|
||||
tests/test_autocompile_publication.c
|
||||
src/autocompile.c
|
||||
|
||||
@@ -46,6 +46,9 @@ static char s_cwd[512];
|
||||
* the loader's READ location, regardless of what the configured command says. */
|
||||
static char s_cache_dir[512];
|
||||
static char s_captures[512];
|
||||
#ifdef _WIN32
|
||||
#include "autocompile_child_env.h"
|
||||
#endif
|
||||
|
||||
enum { AC_IDLE = 0, AC_RUNNING = 1, AC_DONE = 2 };
|
||||
#ifdef _WIN32
|
||||
@@ -1191,10 +1194,18 @@ static int autocompile_request_impl(void) {
|
||||
/* Compilation is opportunistic: it must never outrank the interpreter that
|
||||
* keeps the current frame alive. cmd -> python -> gcc inherit below-normal
|
||||
* priority, while the live compile script also defaults to one worker. */
|
||||
char *child_env = s_cache_dir[0] ? ac_child_environment(s_cache_dir) : NULL;
|
||||
if (s_cache_dir[0] && !child_env) {
|
||||
if (job) CloseHandle(job);
|
||||
CloseHandle(rd); CloseHandle(wr);
|
||||
autocompile_note_failure();
|
||||
return 0;
|
||||
}
|
||||
BOOL ok = CreateProcessA(NULL, full, NULL, NULL, TRUE,
|
||||
CREATE_NO_WINDOW | BELOW_NORMAL_PRIORITY_CLASS |
|
||||
CREATE_SUSPENDED,
|
||||
NULL, s_cwd[0] ? s_cwd : NULL, &si, &pi);
|
||||
child_env, s_cwd[0] ? s_cwd : NULL, &si, &pi);
|
||||
free(child_env);
|
||||
CloseHandle(wr);
|
||||
if (!ok) {
|
||||
if (job) CloseHandle(job);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Windows compiler scratch is private to the child, never the game process. */
|
||||
#ifndef PSX_AUTOCOMPILE_CHILD_ENV_H
|
||||
#define PSX_AUTOCOMPILE_CHILD_ENV_H
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static int ac_env_compare(const void *a, const void *b) {
|
||||
return _stricmp(*(const char *const *)a, *(const char *const *)b);
|
||||
}
|
||||
/* cache is the canonical existing cache directory. Caller frees the returned
|
||||
* sorted ANSI environment block after CreateProcessA. NULL is a hard failure;
|
||||
* do not silently inherit a system-drive TEMP after a scratch setup failure. */
|
||||
static char *ac_child_environment(const char *cache) {
|
||||
char temp_dir[sizeof(s_cache_dir) + 5];
|
||||
char temp_var[sizeof(temp_dir) + 6], tmp_var[sizeof(temp_dir) + 5];
|
||||
int n = snprintf(temp_dir, sizeof(temp_dir), "%s\\tmp", cache);
|
||||
if (n < 0 || (size_t)n >= sizeof(temp_dir)) return NULL;
|
||||
if (!CreateDirectoryA(temp_dir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
return NULL;
|
||||
DWORD attr = GetFileAttributesA(temp_dir);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY)) return NULL;
|
||||
snprintf(temp_var, sizeof(temp_var), "TEMP=%s", temp_dir);
|
||||
snprintf(tmp_var, sizeof(tmp_var), "TMP=%s", temp_dir);
|
||||
char *inherited = GetEnvironmentStringsA();
|
||||
if (!inherited) return NULL;
|
||||
size_t count = 0;
|
||||
for (char *p = inherited; *p; p += strlen(p) + 1) ++count;
|
||||
const char **entries = (const char **)malloc((count + 2) * sizeof(*entries));
|
||||
if (!entries) { FreeEnvironmentStringsA(inherited); return NULL; }
|
||||
size_t used = 0, bytes = 1;
|
||||
for (char *p = inherited; *p; p += strlen(p) + 1) {
|
||||
if (!_strnicmp(p, "TEMP=", 5) || !_strnicmp(p, "TMP=", 4)) continue;
|
||||
entries[used++] = p;
|
||||
}
|
||||
entries[used++] = temp_var;
|
||||
entries[used++] = tmp_var;
|
||||
qsort(entries, used, sizeof(*entries), ac_env_compare);
|
||||
for (size_t i = 0; i < used; ++i) bytes += strlen(entries[i]) + 1;
|
||||
char *block = (char *)malloc(bytes);
|
||||
if (block) {
|
||||
char *out = block;
|
||||
for (size_t i = 0; i < used; ++i) {
|
||||
size_t length = strlen(entries[i]) + 1;
|
||||
memcpy(out, entries[i], length); out += length;
|
||||
}
|
||||
*out = 0;
|
||||
}
|
||||
free(entries);
|
||||
FreeEnvironmentStringsA(inherited);
|
||||
return block;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Real child launch: private TEMP/TMP, inherited variables, parent isolation. */
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static char s_cache_dir[512]; /* same input capacity as autocompile.c */
|
||||
#include "autocompile_child_env.h"
|
||||
#define CHECK(x) do { if (!(x)) { fprintf(stderr,"FAIL line %d: %s\n",__LINE__,#x); return 1; } } while (0)
|
||||
int main(int argc, char **argv) {
|
||||
char temp[1024], tmp[1024];
|
||||
if (argc == 3 && !strcmp(argv[1], "--child")) {
|
||||
CHECK(GetEnvironmentVariableA("TEMP", temp, sizeof(temp)) > 0);
|
||||
CHECK(GetEnvironmentVariableA("TMP", tmp, sizeof(tmp)) > 0);
|
||||
CHECK(!strcmp(temp, argv[2]) && !strcmp(tmp, argv[2]));
|
||||
char marker[32];
|
||||
CHECK(GetEnvironmentVariableA("PSX_AC_TEMP_TEST", marker, sizeof(marker)) > 0);
|
||||
CHECK(!strcmp(marker, "preserved"));
|
||||
return 0;
|
||||
}
|
||||
char cwd[512], cache[600], expected[610], exe[1024], cmd[2300];
|
||||
CHECK(GetCurrentDirectoryA(sizeof(cwd), cwd) > 0);
|
||||
CHECK(GetEnvironmentVariableA("TEMP", temp, sizeof(temp)) > 0);
|
||||
CHECK(GetEnvironmentVariableA("TMP", tmp, sizeof(tmp)) > 0);
|
||||
CHECK(SetEnvironmentVariableA("PSX_AC_TEMP_TEST", "preserved"));
|
||||
snprintf(cache, sizeof(cache), "%s\\autocompile-child-cache", cwd);
|
||||
CHECK(CreateDirectoryA(cache, NULL) || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||
char *env = ac_child_environment(cache);
|
||||
CHECK(env != NULL);
|
||||
int temps = 0, tmps = 0;
|
||||
const char *previous = NULL;
|
||||
for (char *p = env; *p; p += strlen(p) + 1) {
|
||||
CHECK(!previous || _stricmp(previous, p) <= 0);
|
||||
if (!_strnicmp(p, "TEMP=", 5)) ++temps;
|
||||
if (!_strnicmp(p, "TMP=", 4)) ++tmps;
|
||||
previous = p;
|
||||
}
|
||||
CHECK(temps == 1 && tmps == 1);
|
||||
snprintf(expected, sizeof(expected), "%s\\tmp", cache);
|
||||
CHECK(GetModuleFileNameA(NULL, exe, sizeof(exe)) > 0);
|
||||
snprintf(cmd, sizeof(cmd), "\"%s\" --child \"%s\"", exe, expected);
|
||||
STARTUPINFOA si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si);
|
||||
CHECK(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW,
|
||||
env, cwd, &si, &pi));
|
||||
free(env);
|
||||
CHECK(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
|
||||
DWORD code = 1; CHECK(GetExitCodeProcess(pi.hProcess, &code));
|
||||
CloseHandle(pi.hThread); CloseHandle(pi.hProcess); CHECK(code == 0);
|
||||
char after[1024];
|
||||
CHECK(GetEnvironmentVariableA("TEMP", after, sizeof(after)) > 0 && !strcmp(after,temp));
|
||||
CHECK(GetEnvironmentVariableA("TMP", after, sizeof(after)) > 0 && !strcmp(after,tmp));
|
||||
/* A file occupying <cache>/tmp must refuse, never inherit another TEMP. */
|
||||
snprintf(cache, sizeof(cache), "%s\\autocompile-blocked-cache", cwd);
|
||||
CHECK(CreateDirectoryA(cache, NULL) || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||
snprintf(expected, sizeof(expected), "%s\\tmp", cache);
|
||||
FILE *file = fopen(expected, "wb"); CHECK(file != NULL); fclose(file);
|
||||
CHECK(ac_child_environment(cache) == NULL);
|
||||
puts("PASS: compiler child gets cache scratch; parent TEMP/TMP stay unchanged; invalid scratch refuses");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user