diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 8465c29d..3f26623a 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -53,8 +53,19 @@ jobs: - name: run-torture shell: cmd 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 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 torture || exit /b 1 diff --git a/build.bat b/build.bat index 002d4370..f4d482a6 100644 --- a/build.bat +++ b/build.bat @@ -82,7 +82,6 @@ set clang_out= -o set clang_linker= -Xlinker :: --- Per-Build Settings ----------------------------------------------------- -set link_dll=-DLL set link_icon=logo.res if "%msvc%"=="1" set linker=%cl_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 "%msvc%"=="1" set rc=call 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 ---------------------------------------------- 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 "%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_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 "%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 diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 3df719c1..9918af6e 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -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) { RB_File *f = n->v; 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(); diff --git a/src/torture/torture.c b/src/torture/torture.c index 31ce4f0a..702caa4f 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -9,6 +9,7 @@ global B32 g_verbose; global B32 g_redirect_stdout = 1; global B32 g_stop_on_first_fail_or_crash = 1; global String8 g_linker; +global String8 g_test_data; // tests 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); } +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 t_run_caller(void *raw_ctx) { Temp scratch = scratch_begin(0,0); T_RunCtx *ctx = raw_ctx; + String8List test_out = {0}; 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); } @@ -131,7 +147,9 @@ t_cl_path(void) ArenaParams params = { .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer }; Arena *arena = arena_alloc_(¶ms); #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 path = str8_lit("cl"); #endif @@ -159,14 +177,14 @@ t_radlink_path(void) } internal String8 -t_src_path(void) +t_cwd_path(void) { local_persist U8 path[4096] = {0}; if (path[0] == 0) { Temp scratch = scratch_begin(0, 0); String8 cwd = os_get_current_path(scratch.arena); cwd = str8_chop_last_slash(cwd); - cwd = str8f(scratch.arena, "%S/src", cwd); + cwd = str8f(scratch.arena, "%S", cwd); MemoryCopyStr8(path, cwd); path[cwd.size] = 0; scratch_end(scratch); @@ -174,8 +192,22 @@ t_src_path(void) 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 -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); @@ -200,6 +232,7 @@ t_invoke_(String8 exe_path, String8 cmdline, U64 timeout, Arena *output_arena, S OS_ProcessLaunchParams launch_opts = { .path = g_wdir, .inherit_env = 1, + .env = env, .stdout_file = write_pipe_handle, .stderr_file = write_pipe_handle, .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; } +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 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 // @@ -390,6 +440,13 @@ t_entry_point(CmdLine *cmdline) 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")); + // 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 { CmdLineOpt *out_opt = cmd_line_opt_from_string(cmdline, str8_lit("out")); diff --git a/src/torture/torture.h b/src/torture/torture.h index 1c8cda0a..161f1024 100644 --- a/src/torture/torture.h +++ b/src/torture/torture.h @@ -20,8 +20,8 @@ typedef struct char *fail_cond; } T_RunResult; -#define T_RunSig(name) void t_##name(Arena *arena, T_RunResult *result_out) -typedef void (*T_Run)(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, String8List *test_out); 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_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_cl_path(void); internal String8 t_radlink_path(void); +internal String8 t_cwd_path(void); internal String8 t_src_path(void); internal B32 t_invoke(String8 exe, String8 cmdline, U64 timeout); diff --git a/src/torture/torture_main.c b/src/torture/torture_main.c index 8c8f6eca..760b1bb9 100644 --- a/src/torture/torture_main.c +++ b/src/torture/torture_main.c @@ -80,6 +80,7 @@ #include "torture_radlink.c" #include "torture_dwarf.c" #include "torture_d2r.c" +#include "torture_p2r.c" //////////////////////////////// diff --git a/src/torture/torture_p2r.c b/src/torture/torture_p2r.c new file mode 100644 index 00000000..7b478705 --- /dev/null +++ b/src/torture/torture_p2r.c @@ -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 + diff --git a/src/torture/torture_radlink.c b/src/torture/torture_radlink.c index 404aa8d9..69936fef 100644 --- a/src/torture/torture_radlink.c +++ b/src/torture/torture_radlink.c @@ -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 out = {0}; - t_invoke_(exe_path, str8_zero(), max_U64, scratch.arena, &out); - if (g_last_exit_code == 0) { - goto exit; - } + + char *old_path_cstr = getenv("PATH"); + 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;