From eaef647957ca5e085eea299cfa9f699c6afe6d8f Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 14 Nov 2023 21:42:19 -0500 Subject: [PATCH] Make c func `abspath` consistent on Windows. Fix tracking path conversion. (#52140) Explanation for the `GetFullPathName` behavior https://developercommunity.visualstudio.com/t/GetFullPath-fails-if-given-empty-string/483359#T-N486167 --- src/init.c | 11 ++++++++++- test/cmdlineargs.jl | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/init.c b/src/init.c index 893032543db82..3e4bbf4e077bc 100644 --- a/src/init.c +++ b/src/init.c @@ -575,6 +575,14 @@ static char *abspath(const char *in, int nprefix) } } #else + // GetFullPathName intentionally errors if given an empty string so manually insert `.` to invoke cwd + char *in2 = (char*)malloc_s(JL_PATH_MAX); + if (strlen(in) - nprefix == 0) { + memcpy(in2, in, nprefix); + in2[nprefix] = '.'; + in2[nprefix+1] = '\0'; + in = in2; + } DWORD n = GetFullPathName(in + nprefix, 0, NULL, NULL); if (n <= 0) { jl_error("fatal error: jl_options.image_file path too long or GetFullPathName failed"); @@ -585,6 +593,7 @@ static char *abspath(const char *in, int nprefix) jl_error("fatal error: jl_options.image_file path too long or GetFullPathName failed"); } memcpy(out, in, nprefix); + free(in2); #endif return out; } @@ -680,7 +689,7 @@ static void jl_resolve_sysimg_location(JL_IMAGE_SEARCH rel) if (jl_options.output_code_coverage) jl_options.output_code_coverage = absformat(jl_options.output_code_coverage); if (jl_options.tracked_path) - jl_options.tracked_path = absformat(jl_options.tracked_path); + jl_options.tracked_path = abspath(jl_options.tracked_path, 0); const char **cmdp = jl_options.cmds; if (cmdp) { diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index fda4ce2699292..26cee030f9110 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -473,10 +473,47 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` @test occursin(expected, got) || (expected, got) @test_broken occursin(expected_good, got) + # Ask for coverage in current directory + tdir = dirname(realpath(inputfile)) + cd(tdir) do + # there may be atrailing separator here so use rstrip + @test readchomp(`$exename -E "(Base.JLOptions().code_coverage, rstrip(unsafe_string(Base.JLOptions().tracked_path), '/'))" -L $inputfile + --code-coverage=$covfile --code-coverage=@`) == "(3, $(repr(tdir)))" + end + @test isfile(covfile) + got = read(covfile, String) + rm(covfile) + @test occursin(expected, got) || (expected, got) + @test_broken occursin(expected_good, got) + + # Ask for coverage in relative directory + tdir = dirname(realpath(inputfile)) + cd(dirname(tdir)) do + @test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile + --code-coverage=$covfile --code-coverage=@testhelpers`) == "(3, $(repr(tdir)))" + end + @test isfile(covfile) + got = read(covfile, String) + rm(covfile) + @test occursin(expected, got) || (expected, got) + @test_broken occursin(expected_good, got) + + # Ask for coverage in relative directory with dot-dot notation + tdir = dirname(realpath(inputfile)) + cd(tdir) do + @test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile + --code-coverage=$covfile --code-coverage=@../testhelpers`) == "(3, $(repr(tdir)))" + end + @test isfile(covfile) + got = read(covfile, String) + rm(covfile) + @test occursin(expected, got) || (expected, got) + @test_broken occursin(expected_good, got) + # Ask for coverage in a different directory tdir = mktempdir() # a dir that contains no code @test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile - --code-coverage=$covfile --code-coverage=@$tdir`) == "(3, $(repr(tdir)))" + --code-coverage=$covfile --code-coverage=@$tdir`) == "(3, $(repr(realpath(tdir))))" @test isfile(covfile) got = read(covfile, String) @test isempty(got)