Skip to content

Commit ec1fc03

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 ec1fc03

File tree

4 files changed

+47
-33
lines changed

4 files changed

+47
-33
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: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -296,22 +296,35 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
296296

297297
// Stop the search when the process doesn't have permissions
298298
// to walk upwards
299-
if (is_permissions_enabled &&
300-
!env->permission()->is_granted(
301-
env,
302-
permission::PermissionScope::kFileSystemRead,
303-
current_path.generic_string())) [[unlikely]] {
304-
return nullptr;
299+
if (is_permissions_enabled) {
300+
std::string generic_path;
301+
#ifdef _WIN32
302+
generic_path = ConvertWideToUTF8(current_path.generic_wstring());
303+
#else // _WIN32
304+
generic_path = current_path.generic_string();
305+
#endif // _WIN32
306+
//
307+
if (!env->permission()->is_granted(
308+
env, permission::PermissionScope::kFileSystemRead, generic_path))
309+
[[unlikely]] {
310+
return nullptr;
311+
}
305312
}
306313

307314
// Check if the path ends with `/node_modules`
308-
if (current_path.generic_string().ends_with("/node_modules")) {
315+
if (current_path.filename() == "node_modules") {
309316
return nullptr;
310317
}
311318

312319
auto package_json_path = current_path / "package.json";
313-
auto package_json =
314-
GetPackageJSON(realm, package_json_path.string(), nullptr);
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
327+
auto package_json = GetPackageJSON(realm, package_json_path_str, nullptr);
315328
if (package_json != nullptr) {
316329
return package_json;
317330
}
@@ -341,7 +354,7 @@ void BindingData::GetNearestParentPackageJSONType(
341354
std::filesystem::path path;
342355

343356
#ifdef _WIN32
344-
std::wstring wide_path = ConvertToWideString(path_value_str, GetACP());
357+
std::wstring wide_path = ConvertToWideString(path_value_str, CP_UTF8);
345358
path = std::filesystem::path(wide_path);
346359
#else
347360
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)