Skip to content

Commit 919cc0b

Browse files
committed
src: use CP_UTF8 for wide file names on win32
`src/node_modules.cc` needs to be consistent with `src/node_file.cc` in how it translates the utf8 strings to `std::wstring` otherwise we might end up in situation where we can read the source code of imported package from disk, but fail to recognize that it is an ESM (or CJS) and cause runtime errors. This type of error is possible on Windows when the path contains unicode characters and "Language for non-Unicode programs" is set to "Chinese (Traditional, Taiwan)". See: #58768
1 parent 0b621d2 commit 919cc0b

File tree

4 files changed

+46
-31
lines changed

4 files changed

+46
-31
lines changed

src/node_file.cc

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3173,29 +3173,6 @@ static void GetFormatOfExtensionlessFile(
31733173
#define BufferValueToPath(str) \
31743174
std::filesystem::path(ConvertToWideString(str.ToString(), CP_UTF8))
31753175

3176-
std::string ConvertWideToUTF8(const std::wstring& wstr) {
3177-
if (wstr.empty()) return std::string();
3178-
3179-
int size_needed = WideCharToMultiByte(CP_UTF8,
3180-
0,
3181-
&wstr[0],
3182-
static_cast<int>(wstr.size()),
3183-
nullptr,
3184-
0,
3185-
nullptr,
3186-
nullptr);
3187-
std::string strTo(size_needed, 0);
3188-
WideCharToMultiByte(CP_UTF8,
3189-
0,
3190-
&wstr[0],
3191-
static_cast<int>(wstr.size()),
3192-
&strTo[0],
3193-
size_needed,
3194-
nullptr,
3195-
nullptr);
3196-
return strTo;
3197-
}
3198-
31993176
#define PathToString(path) ConvertWideToUTF8(path.wstring());
32003177

32013178
#else // _WIN32

src/node_modules.cc

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,24 +294,38 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
294294
break;
295295
}
296296

297+
// Check if the path ends with `/node_modules`
298+
if (current_path.filename() == "node_modules") {
299+
return nullptr;
300+
}
301+
302+
std::string generic_path;
303+
#ifdef _WIN32
304+
generic_path = ConvertWideToUTF8(current_path.generic_wstring());
305+
#else // _WIN32
306+
generic_path = current_path.generic_string();
307+
#endif // _WIN32
308+
297309
// Stop the search when the process doesn't have permissions
298310
// to walk upwards
299311
if (is_permissions_enabled &&
300312
!env->permission()->is_granted(
301313
env,
302314
permission::PermissionScope::kFileSystemRead,
303-
current_path.generic_string())) [[unlikely]] {
304-
return nullptr;
305-
}
306-
307-
// Check if the path ends with `/node_modules`
308-
if (current_path.generic_string().ends_with("/node_modules")) {
315+
generic_path)) [[unlikely]] {
309316
return nullptr;
310317
}
311318

312319
auto package_json_path = current_path / "package.json";
320+
321+
std::string package_json_path_str;
322+
#ifdef _WIN32
323+
package_json_path_str = ConvertWideToUTF8(package_json_path.wstring());
324+
#else // _WIN32
325+
package_json_path_str = package_json_path.string();
326+
#endif // _WIN32
313327
auto package_json =
314-
GetPackageJSON(realm, package_json_path.string(), nullptr);
328+
GetPackageJSON(realm, package_json_path_str, nullptr);
315329
if (package_json != nullptr) {
316330
return package_json;
317331
}
@@ -341,7 +355,7 @@ void BindingData::GetNearestParentPackageJSONType(
341355
std::filesystem::path path;
342356

343357
#ifdef _WIN32
344-
std::wstring wide_path = ConvertToWideString(path_value_str, GetACP());
358+
std::wstring wide_path = ConvertToWideString(path_value_str, CP_UTF8);
345359
path = std::filesystem::path(wide_path);
346360
#else
347361
path = std::filesystem::path(path_value_str);

src/util-inl.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,29 @@ inline std::wstring ConvertToWideString(const std::string& str,
731731
size_needed);
732732
return wstrTo;
733733
}
734+
735+
std::string ConvertWideToUTF8(const std::wstring& wstr) {
736+
if (wstr.empty()) return std::string();
737+
738+
int size_needed = WideCharToMultiByte(CP_UTF8,
739+
0,
740+
&wstr[0],
741+
static_cast<int>(wstr.size()),
742+
nullptr,
743+
0,
744+
nullptr,
745+
nullptr);
746+
std::string strTo(size_needed, 0);
747+
WideCharToMultiByte(CP_UTF8,
748+
0,
749+
&wstr[0],
750+
static_cast<int>(wstr.size()),
751+
&strTo[0],
752+
size_needed,
753+
nullptr,
754+
nullptr);
755+
return strTo;
756+
}
734757
#endif // _WIN32
735758

736759
inline v8::MaybeLocal<v8::Object> NewDictionaryInstance(

src/util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,7 @@ class JSONOutputStream final : public v8::OutputStream {
10391039
// case insensitive.
10401040
inline bool IsWindowsBatchFile(const char* filename);
10411041
inline std::wstring ConvertToWideString(const std::string& str, UINT code_page);
1042+
inline std::string ConvertWideToUTF8(const std::wstring& wstr);
10421043
#endif // _WIN32
10431044

10441045
// A helper to create a new instance of the dictionary template.

0 commit comments

Comments
 (0)