diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index d9f3c70ffddc..195e18a32be4 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -1379,14 +1379,27 @@ static bool delimiterMatches(unsigned CustomDelimiterLen, const char *&BytesPtr, /// advanceIfMultilineDelimiter - Centralized check for multiline delimiter. static bool advanceIfMultilineDelimiter(unsigned CustomDelimiterLen, - const char *&CurPtr, + const char *&CurPtr, const char *EndPtr, DiagnosticEngine *Diags, bool IsOpening = false) { + auto scanDelimiter = [&]() -> const char * { + // CurPtr here points to the character after `"`. + const char *TmpPtr = CurPtr; + if (*(TmpPtr - 1) == '"' && + diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags) && + diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags)) { + return TmpPtr; + } + return nullptr; + }; + auto *DelimEnd = scanDelimiter(); + if (!DelimEnd) + return false; // Test for single-line string literals that resemble multiline delimiter. - const char *TmpPtr = CurPtr + 1; + const char *TmpPtr = DelimEnd - 1; if (IsOpening && CustomDelimiterLen) { - while (*TmpPtr != '\r' && *TmpPtr != '\n') { + while (TmpPtr != EndPtr && *TmpPtr != '\r' && *TmpPtr != '\n') { if (*TmpPtr == '"') { if (delimiterMatches(CustomDelimiterLen, ++TmpPtr, nullptr)) { return false; @@ -1397,15 +1410,8 @@ static bool advanceIfMultilineDelimiter(unsigned CustomDelimiterLen, } } - TmpPtr = CurPtr; - if (*(TmpPtr - 1) == '"' && - diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags) && - diagnoseZeroWidthMatchAndAdvance('"', TmpPtr, Diags)) { - CurPtr = TmpPtr; - return true; - } - - return false; + CurPtr = DelimEnd; + return true; } /// 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, DiagnosticEngine *D = EmitDiagnostics ? getTokenDiags() : nullptr; auto TmpPtr = CurPtr; - if (IsMultilineString && - !advanceIfMultilineDelimiter(CustomDelimiterLen, TmpPtr, D)) + if (IsMultilineString && !advanceIfMultilineDelimiter( + CustomDelimiterLen, TmpPtr, BufferEnd, D)) return '"'; if (CustomDelimiterLen && !delimiterMatches(CustomDelimiterLen, TmpPtr, D, /*IsClosing=*/true)) @@ -1587,9 +1593,8 @@ static const char *skipToEndOfInterpolatedExpression(const char *CurPtr, if (!inStringLiteral()) { // Open string literal. OpenDelimiters.push_back(CurPtr[-1]); - AllowNewline.push_back(advanceIfMultilineDelimiter(CustomDelimiterLen, - CurPtr, nullptr, - true)); + AllowNewline.push_back(advanceIfMultilineDelimiter( + CustomDelimiterLen, CurPtr, EndPtr, nullptr, true)); CustomDelimiter.push_back(CustomDelimiterLen); continue; } @@ -1602,7 +1607,8 @@ static const char *skipToEndOfInterpolatedExpression(const char *CurPtr, // Multi-line string can only be closed by '"""'. if (AllowNewline.back() && - !advanceIfMultilineDelimiter(CustomDelimiterLen, CurPtr, nullptr)) + !advanceIfMultilineDelimiter(CustomDelimiterLen, CurPtr, EndPtr, + nullptr)) continue; // Check whether we have equivalent number of '#'s. @@ -1947,7 +1953,7 @@ void Lexer::lexStringLiteral(unsigned CustomDelimiterLen) { assert((QuoteChar == '"' || QuoteChar == '\'') && "Unexpected start"); bool IsMultilineString = advanceIfMultilineDelimiter( - CustomDelimiterLen, CurPtr, getTokenDiags(), true); + CustomDelimiterLen, CurPtr, BufferEnd, getTokenDiags(), true); if (IsMultilineString && *CurPtr != '\n' && *CurPtr != '\r') diagnose(CurPtr, diag::lex_illegal_multiline_string_start) .fixItInsert(Lexer::getSourceLoc(CurPtr), "\n"); diff --git a/validation-test/compiler_crashers_fixed/Parser-consumeTokenWithoutFeedingReceiver-dff2d1.swift b/validation-test/compiler_crashers_fixed/Parser-consumeTokenWithoutFeedingReceiver-dff2d1.swift new file mode 100644 index 000000000000..f5b614d05820 --- /dev/null +++ b/validation-test/compiler_crashers_fixed/Parser-consumeTokenWithoutFeedingReceiver-dff2d1.swift @@ -0,0 +1,10 @@ +// RUN: %empty-directory(%t) + +// RUN: echo '#"' > %t/main1.swift +// RUN: echo -n '#"' > %t/main2.swift + +// RUN: env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib not %target-swift-frontend -typecheck %t/main1.swift +// RUN: env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib not %target-swift-frontend -typecheck %t/main2.swift + +// guardmalloc is incompatible with ASAN +// REQUIRES: no_asan