Skip to content

Commit 74c32ec

Browse files
authored
Use libuv in absrealpath to fix Korean path names on Windows (#59910)
Fixes #33486 The issue in #33486 was caused by the use of `GetFullPathName` on Windows in the `absrealpath` C function. `GetFullPathName` does not always return a UTF-8 encoded path. `absrealpath` is used to set the paths in `jl_options`. So if Julia is run from a non-ASCII directory with a non-UTF-8 locale, the paths in `jl_options` are broken. This PR fixes this by using `uv_fs_realpath` and `uv_cwd` from libuv, which handles conversion of Windows paths to WTF-8.
1 parent c6091de commit 74c32ec

File tree

2 files changed

+12
-34
lines changed

2 files changed

+12
-34
lines changed

src/jlapi.c

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,21 +1173,20 @@ static const char *absformat(const char *in)
11731173
static char *absrealpath(const char *in, int nprefix)
11741174
{ // compute an absolute realpath location, so that chdir doesn't change the file reference
11751175
// ignores (copies directly over) nprefix characters at the start of abspath
1176-
#ifndef _OS_WINDOWS_
1177-
char *out = realpath(in + nprefix, NULL);
1178-
if (out) {
1179-
if (nprefix > 0) {
1180-
size_t sz = strlen(out) + 1;
1181-
char *cpy = (char*)malloc_s(sz + nprefix);
1182-
memcpy(cpy, in, nprefix);
1183-
memcpy(cpy + nprefix, out, sz);
1184-
free(out);
1185-
out = cpy;
1186-
}
1176+
char *out;
1177+
uv_fs_t req;
1178+
int realpath_ret = uv_fs_realpath(NULL, &req, in + nprefix, NULL);
1179+
if (realpath_ret >= 0) {
1180+
size_t sz = strlen((char*)(req.ptr)) + 1;
1181+
out = (char*)malloc_s(sz + nprefix);
1182+
memcpy(out, in, nprefix);
1183+
memcpy(out + nprefix, req.ptr, sz);
1184+
uv_fs_req_cleanup(&req);
11871185
}
11881186
else {
1187+
uv_fs_req_cleanup(&req);
11891188
size_t sz = strlen(in + nprefix) + 1;
1190-
if (in[nprefix] == PATHSEPSTRING[0]) {
1189+
if (jl_isabspath(in + nprefix)) {
11911190
out = (char*)malloc_s(sz + nprefix);
11921191
memcpy(out, in, sz + nprefix);
11931192
}
@@ -1205,27 +1204,6 @@ static char *absrealpath(const char *in, int nprefix)
12051204
free(path);
12061205
}
12071206
}
1208-
#else
1209-
// GetFullPathName intentionally errors if given an empty string so manually insert `.` to invoke cwd
1210-
char *in2 = (char*)malloc_s(JL_PATH_MAX);
1211-
if (strlen(in) - nprefix == 0) {
1212-
memcpy(in2, in, nprefix);
1213-
in2[nprefix] = '.';
1214-
in2[nprefix+1] = '\0';
1215-
in = in2;
1216-
}
1217-
DWORD n = GetFullPathName(in + nprefix, 0, NULL, NULL);
1218-
if (n <= 0) {
1219-
jl_error("fatal error: jl_options.image_file path too long or GetFullPathName failed");
1220-
}
1221-
char *out = (char*)malloc_s(n + nprefix);
1222-
DWORD m = GetFullPathName(in + nprefix, n, out + nprefix, NULL);
1223-
if (n != m + 1) {
1224-
jl_error("fatal error: jl_options.image_file path too long or GetFullPathName failed");
1225-
}
1226-
memcpy(out, in, nprefix);
1227-
free(in2);
1228-
#endif
12291207
return out;
12301208
}
12311209

test/cmdlineargs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
580580
tdir = dirname(realpath(inputfile))
581581
cd(tdir) do
582582
# there may be atrailing separator here so use rstrip
583-
@test readchomp(`$cov_exename -E "(Base.JLOptions().code_coverage, rstrip(unsafe_string(Base.JLOptions().tracked_path), '/'))" -L $inputfile
583+
@test readchomp(`$cov_exename -E "(Base.JLOptions().code_coverage, rstrip(unsafe_string(Base.JLOptions().tracked_path), Base.Filesystem.path_separator[1]))" -L $inputfile
584584
--code-coverage=$covfile --code-coverage=@`) == "(3, $(repr(tdir)))"
585585
end
586586
@test isfile(covfile)

0 commit comments

Comments
 (0)