port pdb -> rdi determinism test

This commit is contained in:
Nikita Smith
2026-04-09 13:41:04 -07:00
parent 5f5120144b
commit 85bbfa755a
8 changed files with 215 additions and 16 deletions
+12 -1
View File
@@ -53,8 +53,19 @@ jobs:
- name: run-torture - name: run-torture
shell: cmd shell: cmd
run: | run: |
rem find path to clang
for /f "tokens=*" %%i in ('where clang') do set clang_path=%%~dpi
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
call build asan meta torture radlink radbin "${{matrix.mode}}" "${{matrix.compiler}}" || exit /b 1
rem set clang path before MSVC's clang path
set PATH=%clang_path%;%PATH%
rem parse out clang version number out of --version to build path to the folder with ASAN DLL
for /f "tokens=3 delims=. " %%v in ('clang -v 2^>^&1 ^| findstr version') do set clang_version=%%v
if "${{matrix.compiler}}" == "clang" set PATH=%clang_path%..\lib\clang\%clang_version%\lib\windows;%PATH%
call build asan meta torture radlink radbin mule_main mule_module "${{matrix.mode}}" "${{matrix.compiler}}" || exit /b 1
cd build cd build
torture || exit /b 1 torture || exit /b 1
+3 -2
View File
@@ -82,7 +82,6 @@ set clang_out= -o
set clang_linker= -Xlinker set clang_linker= -Xlinker
:: --- Per-Build Settings ----------------------------------------------------- :: --- Per-Build Settings -----------------------------------------------------
set link_dll=-DLL
set link_icon=logo.res set link_icon=logo.res
if "%msvc%"=="1" set linker=%cl_linker% if "%msvc%"=="1" set linker=%cl_linker%
if "%clang%"=="1" set linker=%clang_linker% if "%clang%"=="1" set linker=%clang_linker%
@@ -94,6 +93,8 @@ if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc if "%clang%"=="1" set rc=call llvm-rc
if "%msvc%"=="1" set link_dll=/link /DLL
if "%clang%"=="1" set link_dll=-Xlinker -DLL
:: --- Choose Compile/Link Lines ---------------------------------------------- :: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug% if "%msvc%"=="1" set compile_debug=%cl_debug%
@@ -147,7 +148,7 @@ if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratc
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1 if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1 if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp %out%mule_inline.obj && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp %out%mule_o2.obj && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp %out%mule_inline.obj && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp %out%mule_o2.obj && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %link_dll% %out%mule_module.dll || exit /b 1
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture_main.c %compile_link% %out%torture.exe || exit /b1 if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture_main.c %compile_link% %out%torture.exe || exit /b1
if "%dwarf_expr_test%"=="1" set didbuild=1 && %compile% ..\src\torture\dwarf_expr_test.c %compile_link% %out%dwarf_expr_test.exe || exit /b1 if "%dwarf_expr_test%"=="1" set didbuild=1 && %compile% ..\src\torture\dwarf_expr_test.c %compile_link% %out%dwarf_expr_test.exe || exit /b1
+5 -2
View File
@@ -1253,13 +1253,16 @@ rb_thread_entry_point(void *p)
} }
} }
//- rjf: dump input files in order //- rjf: dump input files in ordere
for(RB_FileNode *n = input_files.first; n != 0; n = n->next) for(RB_FileNode *n = input_files.first; n != 0; n = n->next)
{ {
RB_File *f = n->v; RB_File *f = n->v;
if(lane_idx() == 0) if(lane_idx() == 0)
{ {
str8_list_pushf(arena, &output_blobs, "// %S (%S)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format")); if(!deterministic)
{
str8_list_pushf(arena, &output_blobs, "// %S (%S)\n\n", f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format"));
}
} }
lane_sync(); lane_sync();
+62 -5
View File
@@ -9,6 +9,7 @@ global B32 g_verbose;
global B32 g_redirect_stdout = 1; global B32 g_redirect_stdout = 1;
global B32 g_stop_on_first_fail_or_crash = 1; global B32 g_stop_on_first_fail_or_crash = 1;
global String8 g_linker; global String8 g_linker;
global String8 g_test_data;
// tests // tests
U64 g_torture_test_count; U64 g_torture_test_count;
@@ -76,13 +77,28 @@ t_make_file_path(Arena *arena, String8 name)
return push_str8f(arena, "%S\\%S", g_wdir, name); return push_str8f(arena, "%S\\%S", g_wdir, name);
} }
internal B32
t_make_dir(String8 name)
{
Temp scratch = scratch_begin(0,0);
B32 is_ok = os_make_directory(t_make_file_path(scratch.arena, name));
scratch_end(scratch);
return is_ok;
}
internal void internal void
t_run_caller(void *raw_ctx) t_run_caller(void *raw_ctx)
{ {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
T_RunCtx *ctx = raw_ctx; T_RunCtx *ctx = raw_ctx;
String8List test_out = {0};
ctx->result.status = T_RunStatus_Pass; ctx->result.status = T_RunStatus_Pass;
ctx->run(scratch.arena, &ctx->result); ctx->run(scratch.arena, &ctx->result, &test_out);
if (ctx->result.status == T_RunStatus_Fail) {
for EachNode(n, String8Node, test_out.first) {
fprintf(stderr, "%.*s", str8_varg(n->string));
}
}
scratch_end(scratch); scratch_end(scratch);
} }
@@ -131,7 +147,9 @@ t_cl_path(void)
ArenaParams params = { .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer }; ArenaParams params = { .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer };
Arena *arena = arena_alloc_(&params); Arena *arena = arena_alloc_(&params);
#if OS_WINDOWS #if OS_WINDOWS
path = str8_lit("cl.exe"); wchar_t full_cl_path[MAX_PATH];
DWORD full_cl_path_size = SearchPathW(0, L"cl.exe", 0, ArrayCount(full_cl_path), full_cl_path, 0);
path = str8_from_16(arena, str16((U16*)full_cl_path, full_cl_path_size));
#else #else
path = str8_lit("cl"); path = str8_lit("cl");
#endif #endif
@@ -159,14 +177,14 @@ t_radlink_path(void)
} }
internal String8 internal String8
t_src_path(void) t_cwd_path(void)
{ {
local_persist U8 path[4096] = {0}; local_persist U8 path[4096] = {0};
if (path[0] == 0) { if (path[0] == 0) {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
String8 cwd = os_get_current_path(scratch.arena); String8 cwd = os_get_current_path(scratch.arena);
cwd = str8_chop_last_slash(cwd); cwd = str8_chop_last_slash(cwd);
cwd = str8f(scratch.arena, "%S/src", cwd); cwd = str8f(scratch.arena, "%S", cwd);
MemoryCopyStr8(path, cwd); MemoryCopyStr8(path, cwd);
path[cwd.size] = 0; path[cwd.size] = 0;
scratch_end(scratch); scratch_end(scratch);
@@ -174,8 +192,22 @@ t_src_path(void)
return str8_cstring_capped(path, path+sizeof(path)); return str8_cstring_capped(path, path+sizeof(path));
} }
internal String8
t_src_path(void)
{
local_persist U8 path[4096] = {0};
if (path[0] == 0) {
Temp scratch = scratch_begin(0, 0);
String8 src = str8f(scratch.arena, "%S/src", t_cwd_path());
MemoryCopyStr8(path, src);
path[src.size] = 0;
scratch_end(scratch);
}
return str8_cstring_capped(path, path+sizeof(path));
}
internal B32 internal B32
t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, String8 *output_out) t_invoke_env(String8 exe_path, String8 cmdline, String8List env, U64 timeout, Arena *output_arena, String8 *output_out)
{ {
Temp scratch = scratch_begin(&output_arena,1); Temp scratch = scratch_begin(&output_arena,1);
@@ -200,6 +232,7 @@ t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, S
OS_ProcessLaunchParams launch_opts = { OS_ProcessLaunchParams launch_opts = {
.path = g_wdir, .path = g_wdir,
.inherit_env = 1, .inherit_env = 1,
.env = env,
.stdout_file = write_pipe_handle, .stdout_file = write_pipe_handle,
.stderr_file = write_pipe_handle, .stderr_file = write_pipe_handle,
.cmd_line = lnk_arg_list_parse_windows_rules(scratch.arena, cmdline), .cmd_line = lnk_arg_list_parse_windows_rules(scratch.arena, cmdline),
@@ -252,6 +285,12 @@ t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, S
return is_ok; return is_ok;
} }
internal B32
t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, String8 *output_out)
{
return t_invoke_env(exe_path, cmdline, (String8List){0}, timeout, output_arena, output_out);
}
internal B32 internal B32
t_invoke(String8 exe_path, String8 cmdline, U64 timeout) t_invoke(String8 exe_path, String8 cmdline, U64 timeout)
{ {
@@ -368,6 +407,17 @@ t_entry_point(CmdLine *cmdline)
} }
} }
//
// Handle -test_data
//
{
g_test_data = cmd_line_string(cmdline, str8_lit("test_data"));
if (g_test_data.size == 0) {
g_test_data = str8f(scratch.arena, "%S/build", t_cwd_path());
//fprintf(stderr, "WARNING: The test data folder path was not specified. Specify the path when running the program, assuming: %.*s --test_data:%.*s\n", str8_varg(cmdline->exe_name), str8_varg(g_test_data));
}
}
// //
// Handle optional -target // Handle optional -target
// //
@@ -390,6 +440,13 @@ t_entry_point(CmdLine *cmdline)
g_redirect_stdout = !cmd_line_has_flag(cmdline, str8_lit("print_stdout")); g_redirect_stdout = !cmd_line_has_flag(cmdline, str8_lit("print_stdout"));
g_stop_on_first_fail_or_crash = !cmd_line_has_flag(cmdline, str8_lit("keep_going")); g_stop_on_first_fail_or_crash = !cmd_line_has_flag(cmdline, str8_lit("keep_going"));
// default options when running under debugger
#if OS_WINDOWS
if (!cmd_line_has_flag(cmdline, str8_lit("print_stdout")) && IsDebuggerPresent()) {
g_redirect_stdout = 0;
}
#endif
// Handle -out // Handle -out
{ {
CmdLineOpt *out_opt = cmd_line_opt_from_string(cmdline, str8_lit("out")); CmdLineOpt *out_opt = cmd_line_opt_from_string(cmdline, str8_lit("out"));
+4 -2
View File
@@ -20,8 +20,8 @@ typedef struct
char *fail_cond; char *fail_cond;
} T_RunResult; } T_RunResult;
#define T_RunSig(name) void t_##name(Arena *arena, T_RunResult *result_out) #define T_RunSig(name) void t_##name(Arena *arena, T_RunResult *result_out, String8List *test_out)
typedef void (*T_Run)(Arena *arena, T_RunResult *result_out); typedef void (*T_Run)(Arena *arena, T_RunResult *result_out, String8List *test_out);
typedef struct typedef struct
{ {
@@ -63,6 +63,7 @@ extern T_Test g_torture_tests[0xffffff];
#define T_Ok(c) do { if (!(c)) { result_out->fail_file = __FILE__; result_out->fail_line = __LINE__; result_out->fail_cond = Stringify(c); result_out->status = T_RunStatus_Fail; return; } } while(0) #define T_Ok(c) do { if (!(c)) { result_out->fail_file = __FILE__; result_out->fail_line = __LINE__; result_out->fail_cond = Stringify(c); result_out->status = T_RunStatus_Fail; return; } } while(0)
#define T_MatchLinef(out, ...) T_Ok(t_match_linef(out, __VA_ARGS__)) #define T_MatchLinef(out, ...) T_Ok(t_match_linef(out, __VA_ARGS__))
#define t_outf(...) str8_list_pushf(arena, test_out, ## __VA_ARGS__)
//////////////////////////////// ////////////////////////////////
@@ -81,6 +82,7 @@ internal T_RunResult t_run(T_Run run);
internal String8 t_radbin_path(void); internal String8 t_radbin_path(void);
internal String8 t_cl_path(void); internal String8 t_cl_path(void);
internal String8 t_radlink_path(void); internal String8 t_radlink_path(void);
internal String8 t_cwd_path(void);
internal String8 t_src_path(void); internal String8 t_src_path(void);
internal B32 t_invoke(String8 exe, String8 cmdline, U64 timeout); internal B32 t_invoke(String8 exe, String8 cmdline, U64 timeout);
+1
View File
@@ -80,6 +80,7 @@
#include "torture_radlink.c" #include "torture_radlink.c"
#include "torture_dwarf.c" #include "torture_dwarf.c"
#include "torture_d2r.c" #include "torture_d2r.c"
#include "torture_p2r.c"
//////////////////////////////// ////////////////////////////////
+123
View File
@@ -0,0 +1,123 @@
#define T_Group "p2r"
#if OS_WINDOWS
T_BeginTest(p2r_determ)
{
U64 num_repeats_per_pdb = 32;
String8 pdb_paths[] =
{
push_str8f(arena, "%S/mule_main.pdb", g_test_data),
push_str8f(arena, "%S/mule_module.pdb", g_test_data),
};
for EachElement(pdb_idx, pdb_paths)
{
// rjf: unpack paths, make output directory
String8 pdb_path = path_normalized_from_string(arena, pdb_paths[pdb_idx]);
// rjf: generate all RDIs
String8List rdi_paths = {0};
String8List dump_paths = {0};
{
OS_HandleList processes = {0};
for EachIndex(repeat_idx, num_repeats_per_pdb)
{
String8 rdi_name = push_str8f(arena, "repeat_%I64u.rdi", repeat_idx);
String8 rdi_path = t_make_file_path(arena, rdi_name);
str8_list_push(arena, &rdi_paths, rdi_path);
String8 cmdl = str8f(arena, "radbin -rdi -deterministic %S -out:%S", pdb_path, rdi_path);
OS_Handle process_handle = os_cmd_line_launch(cmdl);
T_Ok(!os_handle_match(os_handle_zero(), process_handle));
os_handle_list_push(arena, &processes, process_handle);
}
// wait on the converters
for EachNode(n, OS_HandleNode, processes.first) { os_process_join(n->v, max_U64, 0); }
}
// rjf: generate all dumps
{
OS_HandleList processes = {0};
for EachNode(n, String8Node, rdi_paths.first)
{
String8 rdi_path = n->string;
String8 dump_path = push_str8f(arena, "%S.dump", rdi_path);
str8_list_push(arena, &dump_paths, dump_path);
OS_Handle process_handle = os_cmd_line_launchf("radbin -dump -deterministic %S -out:%S", rdi_path, dump_path);
T_Ok(!os_handle_match(os_handle_zero(), process_handle));
os_handle_list_push(arena, &processes, process_handle);
}
for EachNode(n, OS_HandleNode, processes.first) { os_process_join(n->v, max_U64, 0); }
}
// rjf: gather all hashes/paths
U64 rdi_hashes_count = rdi_paths.node_count;
U128 *rdi_hashes = push_array(arena, U128, rdi_hashes_count);
String8 *rdi_paths_array = push_array(arena, String8, rdi_hashes_count);
U64 dump_hashes_count = dump_paths.node_count;
U128 *dump_hashes = push_array(arena, U128, dump_hashes_count);
String8 *dump_paths_array = push_array(arena, String8, dump_hashes_count);
{
U64 idx = 0;
for EachNode(n, String8Node, rdi_paths.first)
{
Temp scratch = scratch_begin(0, 0);
String8 rdi_path = n->string;
String8 path = rdi_path;
T_Ok(path.size);
String8 data = os_data_from_file_path(scratch.arena, path);
T_Ok(data.size);
rdi_hashes [idx] = u128_hash_from_str8(data);
rdi_paths_array[idx] = path;
scratch_end(scratch);
idx += 1;
}
}
{
U64 idx = 0;
for EachNode(n, String8Node, dump_paths.first)
{
Temp scratch = scratch_begin(0, 0);
String8 path = n->string;
T_Ok(path.size);
String8 data = os_data_from_file_path(scratch.arena, path);
T_Ok(data.size);
dump_hashes [idx] = u128_hash_from_str8(data);
dump_paths_array[idx] = path;
scratch_end(scratch);
idx += 1;
}
}
// rjf: determine if all hashes match
U64 mismatch_idx = max_U64;
for EachIndex(idx, rdi_hashes_count)
{
if(!u128_match(rdi_hashes[idx], rdi_hashes[0]))
{
mismatch_idx = idx;
break;
}
}
for EachIndex(idx, dump_hashes_count)
{
if(!u128_match(dump_hashes[idx], dump_hashes[0]))
{
mismatch_idx = idx;
break;
}
}
// rjf: output bad case info
if (mismatch_idx != max_U64) {
U64 idx = mismatch_idx;
t_outf(" pdb[%I64u] \"%S\"\n", idx, pdb_path);
t_outf(" rdi[%I64u] 0x%I64x:%I64x \"%S\"\n", idx, rdi_hashes[idx].u64[0], rdi_hashes[idx].u64[1], rdi_paths_array[idx]);
t_outf(" dump[%I64u] 0x%I64x:%I64x \"%S\"\n", idx, dump_hashes[idx].u64[0], dump_hashes[idx].u64[1], dump_paths_array[idx]);
T_Ok(0);
}
}
}
#endif
#undef T_Group
+5 -4
View File
@@ -4773,10 +4773,11 @@ t_radlink_validate_asan_out(String8 obj_name)
String8 exe_path = t_make_file_path(scratch.arena, str8f(scratch.arena, "%S.exe", str8_chop_last_dot(obj_name))); String8 exe_path = t_make_file_path(scratch.arena, str8f(scratch.arena, "%S.exe", str8_chop_last_dot(obj_name)));
String8 out = {0}; String8 out = {0};
t_invoke_(exe_path, str8_zero(), max_U64, scratch.arena, &out);
if (g_last_exit_code == 0) { char *old_path_cstr = getenv("PATH");
goto exit; String8List env = {0};
} str8_list_pushf(scratch.arena, &env, "PATH=%S;%S", str8_chop_last_slash(t_cl_path()), str8_cstring(old_path_cstr));
t_invoke_env(exe_path, str8_zero(), env, max_U64, scratch.arena, &out);
String8 s = out; String8 s = out;