Skip to content

Commit 451b296

Browse files
mai93katre
authored andcommitted
Update threshold for long path shortening to be MAX_PATH - 4
This PR applies the suggested fix for #12310. Although I could not reproduce it. Fixes: #12310 Closes #12941. PiperOrigin-RevId: 362327025
1 parent 80c59de commit 451b296

File tree

2 files changed

+34
-27
lines changed

2 files changed

+34
-27
lines changed

src/main/native/windows/util.cc

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ static bool Contains(const wstring& s, const WCHAR* substr) {
195195
}
196196

197197
wstring AsShortPath(wstring path, wstring* result) {
198+
// Using `MAX_PATH` - 4 (256) instead of `MAX_PATH` to fix
199+
// https://github.com/bazelbuild/bazel/issues/12310
200+
static const size_t kMaxPath = MAX_PATH - 4;
201+
198202
if (path.empty()) {
199203
result->clear();
200204
return L"";
@@ -212,7 +216,7 @@ wstring AsShortPath(wstring path, wstring* result) {
212216
return MakeErrorMessage(WSTR(__FILE__), __LINE__, L"AsShortPath", path,
213217
L"path is not normalized");
214218
}
215-
if (path.size() >= MAX_PATH && !HasSeparator(path)) {
219+
if (path.size() >= kMaxPath && !HasSeparator(path)) {
216220
return MakeErrorMessage(WSTR(__FILE__), __LINE__, L"AsShortPath", path,
217221
L"path is just a file name but too long");
218222
}
@@ -221,28 +225,29 @@ wstring AsShortPath(wstring path, wstring* result) {
221225
L"path is not absolute");
222226
}
223227
// At this point we know the path is either just a file name (shorter than
224-
// MAX_PATH), or an absolute, normalized, Windows-style path (of any length).
228+
// `kMaxPath`), or an absolute, normalized, Windows-style path (of any
229+
// length).
225230

226231
std::replace(path.begin(), path.end(), '/', '\\');
227232
// Fast-track: the path is already short.
228-
if (path.size() < MAX_PATH) {
233+
if (path.size() < kMaxPath) {
229234
*result = path;
230235
return L"";
231236
}
232-
// At this point we know that the path is at least MAX_PATH long and that it's
233-
// absolute, normalized, and Windows-style.
237+
// At this point we know that the path is at least `kMaxPath` long and that
238+
// it's absolute, normalized, and Windows-style.
234239

235240
wstring wlong = wstring(L"\\\\?\\") + path;
236241

237242
// Experience shows that:
238243
// - GetShortPathNameW's result has a "\\?\" prefix if and only if the input
239244
// did too (though this behavior is not documented on MSDN)
240-
// - CreateProcess{A,W} only accept an executable of MAX_PATH - 1 length
245+
// - CreateProcess{A,W} only accept an executable of `MAX_PATH` - 1 length
241246
// Therefore for our purposes the acceptable shortened length is
242-
// MAX_PATH + 4 (null-terminated). That is, MAX_PATH - 1 for the shortened
247+
// `kMaxPath` + 4 (null-terminated). That is, `kMaxPath` - 1 for the shortened
243248
// path, plus a potential "\\?\" prefix that's only there if `wlong` also had
244249
// it and which we'll omit from `result`, plus a null terminator.
245-
static const size_t kMaxShortPath = MAX_PATH + 4;
250+
static const size_t kMaxShortPath = kMaxPath + 4;
246251

247252
WCHAR wshort[kMaxShortPath];
248253
DWORD wshort_size = ::GetShortPathNameW(wlong.c_str(), NULL, 0);

src/test/native/windows/util_test.cc

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@
3434
namespace bazel {
3535
namespace windows {
3636

37-
using std::wstring;
3837
using std::unique_ptr;
3938
using std::wstring;
4039

4140
static const wstring kUncPrefix = wstring(L"\\\\?\\");
41+
// Using `MAX_PATH` - 4 instead of `MAX_PATH` to fix
42+
// https://github.com/bazelbuild/bazel/issues/12310
43+
constexpr size_t kMaxPath = MAX_PATH - 4;
4244

4345
// Retrieves TEST_TMPDIR as a shortened path. Result won't have a "\\?\" prefix.
4446
static void GetShortTempDir(wstring* result) {
@@ -66,11 +68,11 @@ static void GetShortTempDir(wstring* result) {
6668
::GetShortPathNameW(tmpdir.c_str(), buf.get(), size);
6769

6870
// Set the result, omit the "\\?\" prefix.
69-
// Ensure that the result is shorter than MAX_PATH and also has room for a
71+
// Ensure that the result is shorter than `kMaxPath` and also has room for a
7072
// backslash (1 wchar) and a single-letter executable name with .bat
7173
// extension (5 wchars).
7274
*result = wstring(buf.get() + 4);
73-
ASSERT_LT(result->size(), MAX_PATH - 6);
75+
ASSERT_LT(result->size(), kMaxPath - 6);
7476
}
7577

7678
// If `success` is true, returns an empty string, otherwise an error message.
@@ -165,14 +167,14 @@ static wstring DeleteDir(wstring path) {
165167
// `result_path` will be also a short path under `basedir`.
166168
//
167169
// Every directory in `result_path` will be created. The entire length of this
168-
// path will be exactly MAX_PATH - 7 (not including null-terminator).
170+
// path will be exactly `kMaxPath` - 7 (not including null-terminator).
169171
// Just by appending a file name segment between 6 and 8 characters long (i.e.
170172
// "\a.bat", "\ab.bat", or "\abc.bat") the caller can obtain a path that is
171-
// MAX_PATH - 1 long, or MAX_PATH long, or MAX_PATH + 1 long, respectively,
172-
// and cannot be shortened further.
173+
// `kMaxPath` - 1 long, or `kMaxPath` long, or `kMaxPath` + 1 long,
174+
// respectively, and cannot be shortened further.
173175
static void CreateShortDirsUnder(wstring basedir, wstring* result_path) {
174-
ASSERT_LT(basedir.size(), MAX_PATH);
175-
size_t remaining_len = MAX_PATH - 1 - basedir.size();
176+
ASSERT_LT(basedir.size(), kMaxPath);
177+
size_t remaining_len = kMaxPath - 1 - basedir.size();
176178
ASSERT_GE(remaining_len, 6); // has room for suffix "\a.bat"
177179

178180
// If `remaining_len` is odd, make it even.
@@ -188,7 +190,7 @@ static void CreateShortDirsUnder(wstring basedir, wstring* result_path) {
188190
basedir += wstring(L"\\a");
189191
CREATE_DIR(basedir);
190192
}
191-
ASSERT_EQ(basedir.size(), MAX_PATH - 1 - 6);
193+
ASSERT_EQ(basedir.size(), kMaxPath - 1 - 6);
192194
*result_path = basedir;
193195
}
194196

@@ -260,7 +262,7 @@ TEST(WindowsUtilTest, TestAsExecutablePathForCreateProcessBadInputs) {
260262
ASSERT_SHORTENING_FAILS(L"\\bar.exe", L"path is absolute");
261263

262264
wstring dummy = L"hello";
263-
while (dummy.size() < MAX_PATH) {
265+
while (dummy.size() < kMaxPath) {
264266
dummy += dummy;
265267
}
266268
dummy += L".exe";
@@ -281,24 +283,24 @@ TEST(WindowsUtilTest, TestAsExecutablePathForCreateProcessConversions) {
281283
CreateShortDirsUnder(tmpdir, &short_root);
282284

283285
// Assert that we have enough room to append a file name that is just short
284-
// enough to fit into MAX_PATH - 1, or one that's just long enough to make
285-
// the whole path MAX_PATH long or longer.
286-
ASSERT_EQ(short_root.size(), MAX_PATH - 1 - 6);
286+
// enough to fit into `kMaxPath` - 1, or one that's just long enough to make
287+
// the whole path `kMaxPath` long or longer.
288+
ASSERT_EQ(short_root.size(), kMaxPath - 1 - 6);
287289

288290
wstring actual;
289291
wstring error;
290292
for (size_t i = 0; i < 3; ++i) {
291293
wstring wfilename = short_root;
292294

293295
APPEND_FILE_SEGMENT(6 + i, &wfilename);
294-
ASSERT_EQ(wfilename.size(), MAX_PATH - 1 + i);
296+
ASSERT_EQ(wfilename.size(), kMaxPath - 1 + i);
295297

296-
// When i=0 then `wfilename` is MAX_PATH - 1 long, so
298+
// When i=0 then `wfilename` is `kMaxPath` - 1 long, so
297299
// `AsExecutablePathForCreateProcess` will not attempt to shorten it, and
298300
// so it also won't notice that the file doesn't exist. If however we pass
299301
// a non-existent path to CreateProcessA, then it'll fail, so we'll find out
300302
// about this error in production code.
301-
// When i>0 then `wfilename` is at least MAX_PATH long, so
303+
// When i>0 then `wfilename` is at least `kMaxPath` long, so
302304
// `AsExecutablePathForCreateProcess` will attempt to shorten it, but
303305
// because the file doesn't yet exist, the shortening attempt will fail.
304306
if (i > 0) {
@@ -326,14 +328,14 @@ TEST(WindowsUtilTest, TestAsExecutablePathForCreateProcessConversions) {
326328
// Finally construct a path that can and will be shortened. Just walk up a few
327329
// levels in `short_root` and create a long file name that can be shortened.
328330
wstring wshortenable_root = short_root;
329-
while (wshortenable_root.size() > MAX_PATH - 1 - 13) {
331+
while (wshortenable_root.size() > kMaxPath - 1 - 13) {
330332
wshortenable_root =
331333
wshortenable_root.substr(0, wshortenable_root.find_last_of(L'\\'));
332334
}
333335
wstring wshortenable = wshortenable_root + wstring(L"\\") +
334-
wstring(MAX_PATH - wshortenable_root.size(), L'a') +
336+
wstring(kMaxPath - wshortenable_root.size(), L'a') +
335337
wstring(L".bat");
336-
ASSERT_GT(wshortenable.size(), MAX_PATH);
338+
ASSERT_GT(wshortenable.size(), kMaxPath);
337339

338340
// Attempt to shorten. It will fail because the file doesn't exist yet.
339341
ASSERT_SHORTENING_FAILS(wshortenable, L"GetShortPathNameW");

0 commit comments

Comments
 (0)