Skip to content

Commit 20bee09

Browse files
authored
Merge pull request #85889 from hamishknight/overrun
[Parse] Fix buffer overrun in `advanceIfMultilineDelimiter`
2 parents 1627b5f + 0068438 commit 20bee09

File tree

2 files changed

+35
-19
lines changed

2 files changed

+35
-19
lines changed

lib/Parse/Lexer.cpp

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,14 +1379,27 @@ static bool delimiterMatches(unsigned CustomDelimiterLen, const char *&BytesPtr,
13791379

13801380
/// advanceIfMultilineDelimiter - Centralized check for multiline delimiter.
13811381
static bool advanceIfMultilineDelimiter(unsigned CustomDelimiterLen,
1382-
const char *&CurPtr,
1382+
const char *&CurPtr, const char *EndPtr,
13831383
DiagnosticEngine *Diags,
13841384
bool IsOpening = false) {
1385+
auto scanDelimiter = [&]() -> const char * {
1386+
// CurPtr here points to the character after `"`.
1387+
const char *TmpPtr = CurPtr;
1388+
if (*(TmpPtr - 1) == '"' &&
1389+
diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags) &&
1390+
diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags)) {
1391+
return TmpPtr;
1392+
}
1393+
return nullptr;
1394+
};
1395+
auto *DelimEnd = scanDelimiter();
1396+
if (!DelimEnd)
1397+
return false;
13851398

13861399
// Test for single-line string literals that resemble multiline delimiter.
1387-
const char *TmpPtr = CurPtr + 1;
1400+
const char *TmpPtr = DelimEnd - 1;
13881401
if (IsOpening && CustomDelimiterLen) {
1389-
while (*TmpPtr != '\r' && *TmpPtr != '\n') {
1402+
while (TmpPtr != EndPtr && *TmpPtr != '\r' && *TmpPtr != '\n') {
13901403
if (*TmpPtr == '"') {
13911404
if (delimiterMatches(CustomDelimiterLen, ++TmpPtr, nullptr)) {
13921405
return false;
@@ -1397,15 +1410,8 @@ static bool advanceIfMultilineDelimiter(unsigned CustomDelimiterLen,
13971410
}
13981411
}
13991412

1400-
TmpPtr = CurPtr;
1401-
if (*(TmpPtr - 1) == '"' &&
1402-
diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags) &&
1403-
diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags)) {
1404-
CurPtr = TmpPtr;
1405-
return true;
1406-
}
1407-
1408-
return false;
1413+
CurPtr = DelimEnd;
1414+
return true;
14091415
}
14101416

14111417
/// lexCharacter - Read a character and return its UTF32 code. If this is the
@@ -1450,8 +1456,8 @@ unsigned Lexer::lexCharacter(const char *&CurPtr, char StopQuote,
14501456

14511457
DiagnosticEngine *D = EmitDiagnostics ? getTokenDiags() : nullptr;
14521458
auto TmpPtr = CurPtr;
1453-
if (IsMultilineString &&
1454-
!advanceIfMultilineDelimiter(CustomDelimiterLen, TmpPtr, D))
1459+
if (IsMultilineString && !advanceIfMultilineDelimiter(
1460+
CustomDelimiterLen, TmpPtr, BufferEnd, D))
14551461
return '"';
14561462
if (CustomDelimiterLen &&
14571463
!delimiterMatches(CustomDelimiterLen, TmpPtr, D, /*IsClosing=*/true))
@@ -1587,9 +1593,8 @@ static const char *skipToEndOfInterpolatedExpression(const char *CurPtr,
15871593
if (!inStringLiteral()) {
15881594
// Open string literal.
15891595
OpenDelimiters.push_back(CurPtr[-1]);
1590-
AllowNewline.push_back(advanceIfMultilineDelimiter(CustomDelimiterLen,
1591-
CurPtr, nullptr,
1592-
true));
1596+
AllowNewline.push_back(advanceIfMultilineDelimiter(
1597+
CustomDelimiterLen, CurPtr, EndPtr, nullptr, true));
15931598
CustomDelimiter.push_back(CustomDelimiterLen);
15941599
continue;
15951600
}
@@ -1602,7 +1607,8 @@ static const char *skipToEndOfInterpolatedExpression(const char *CurPtr,
16021607

16031608
// Multi-line string can only be closed by '"""'.
16041609
if (AllowNewline.back() &&
1605-
!advanceIfMultilineDelimiter(CustomDelimiterLen, CurPtr, nullptr))
1610+
!advanceIfMultilineDelimiter(CustomDelimiterLen, CurPtr, EndPtr,
1611+
nullptr))
16061612
continue;
16071613

16081614
// Check whether we have equivalent number of '#'s.
@@ -1947,7 +1953,7 @@ void Lexer::lexStringLiteral(unsigned CustomDelimiterLen) {
19471953
assert((QuoteChar == '"' || QuoteChar == '\'') && "Unexpected start");
19481954

19491955
bool IsMultilineString = advanceIfMultilineDelimiter(
1950-
CustomDelimiterLen, CurPtr, getTokenDiags(), true);
1956+
CustomDelimiterLen, CurPtr, BufferEnd, getTokenDiags(), true);
19511957
if (IsMultilineString && *CurPtr != '\n' && *CurPtr != '\r')
19521958
diagnose(CurPtr, diag::lex_illegal_multiline_string_start)
19531959
.fixItInsert(Lexer::getSourceLoc(CurPtr), "\n");
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: echo '#"' > %t/main1.swift
4+
// RUN: echo -n '#"' > %t/main2.swift
5+
6+
// RUN: env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib not %target-swift-frontend -typecheck %t/main1.swift
7+
// RUN: env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib not %target-swift-frontend -typecheck %t/main2.swift
8+
9+
// guardmalloc is incompatible with ASAN
10+
// REQUIRES: no_asan

0 commit comments

Comments
 (0)