Skip to content

Fix includes normalize win32#2723

Open
lygstate wants to merge 4 commits intoninja-build:masterfrom
lygstate:normalize_fixed
Open

Fix includes normalize win32#2723
lygstate wants to merge 4 commits intoninja-build:masterfrom
lygstate:normalize_fixed

Conversation

@lygstate
Copy link

@lygstate lygstate commented Feb 7, 2026

Replace #2552

Use GetFullPathNameW() instead of GetFullPathNameA() to ensure that
normalization works for all long paths on Windows. Adjust unit
tests accordingly.

Fixes ninja-build#2442
@lygstate
Copy link
Author

cc @jhasse


// NOTE: wide_full_size includes the null-terminating character.
std::wstring wide_path;
wide_path.resize(static_cast<size_t>(wide_full_size - 1));
Copy link
Contributor

@zufuliu zufuliu Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think -1 can be omitted, it's not bad to include extra NUL at the end.
here is no need to use static_cast for widen unsigned conversion (DWORD/unsigned long => size_t).
The document for GetFullPathNameW doesn't say [out] LPWSTR lpBuffer parameter can be NULL, needs test to confirm.
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
Edit: the function will check [in] DWORD nBufferLength parameter (zero in the call) first.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mis-understading the size parameter of std::wstring::resize, the std::wstring always have NUL at the end. but the size parameter would not count it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it does not harm to have extra NUL at string end, wide_path.resize(wide_full_size) is simple.

I come up with an optimization idea, but not sure whether worth it.

  1. init std::wstring wide_path(MAX_PATH, 0);, MAX_PATH should works most of time, then do first wide_full_size = GetFullPathNameW() call.
  2. if result wide_full_size large than MAX_PATH, resize wide_path.resize(wide_full_size), then do second wide_full_size = GetFullPathNameW() call.
  3. if wide_full_size is zero, store error message.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a benchmark of this functionality at clparser_perftest.exe that you can use.

Also FYI, I have a PR to optimize the performance of IncludesNormalize that will probably conflict with this PR. If this lands first I don't mind rebasing mine and looking at the performance of it.

wide_path.resize(static_cast<size_t>(wide_full_size - 1));
DWORD wide_full_size2 =
GetFullPathNameW(wide_filename.c_str(), wide_full_size,
const_cast<wchar_t*>(wide_path.data()), NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think const_cast<wchar_t*> is not need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants