Skip to content

Commit 979d0ee

Browse files
committed
[clang] fix out of bounds access in an empty string when lexing a _Pragma with missing string token
The lexer can attempt to lex a _Pragma and crash with an out of bounds string access when it's lexing a _Pragma whose string token is an invalid buffer, e.g. when a module header file from which the macro expansion for that token was deleted from the file system. Differential Revision: https://reviews.llvm.org/D116052
1 parent aee7056 commit 979d0ee

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

clang/lib/Frontend/PrintPreprocessedOutput.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
189189
bool MoveToLine(const Token &Tok, bool RequireStartOfLine) {
190190
PresumedLoc PLoc = SM.getPresumedLoc(Tok.getLocation());
191191
unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine;
192-
bool IsFirstInFile = Tok.isAtStartOfLine() && PLoc.getLine() == 1;
192+
bool IsFirstInFile =
193+
Tok.isAtStartOfLine() && PLoc.isValid() && PLoc.getLine() == 1;
193194
return MoveToLine(TargetLine, RequireStartOfLine) || IsFirstInFile;
194195
}
195196

clang/lib/Lex/Pragma.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,12 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
263263
}
264264

265265
SourceLocation RParenLoc = Tok.getLocation();
266-
std::string StrVal = getSpelling(StrTok);
266+
bool Invalid = false;
267+
std::string StrVal = getSpelling(StrTok, &Invalid);
268+
if (Invalid) {
269+
Diag(PragmaLoc, diag::err__Pragma_malformed);
270+
return;
271+
}
267272

268273
// The _Pragma is lexically sound. Destringize according to C11 6.10.9.1:
269274
// "The string literal is destringized by deleting any encoding prefix,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
// RUN: %clang_cc1 -emit-module -x c -fmodules -I %t/Inputs -fmodule-name=aa %t/Inputs/module.modulemap -o %t/aa.pcm
5+
// RUN: rm %t/Inputs/b.h
6+
// RUN: not %clang_cc1 -E -fmodules -I %t/Inputs -fmodule-file=%t/aa.pcm %s -o - -fallow-pcm-with-compiler-errors 2>&1 | FileCheck %s
7+
8+
//--- Inputs/module.modulemap
9+
module aa {
10+
header "a.h"
11+
header "b.h"
12+
}
13+
14+
//--- Inputs/a.h
15+
#define TEST(x) x
16+
17+
//--- Inputs/b.h
18+
#define SUB "mypragma"
19+
20+
//--- test.c
21+
#include "a.h"
22+
23+
_Pragma(SUB);
24+
int a = TEST(SUB);
25+
26+
// CHECK: int a
27+
// CHECK: 1 error generated

0 commit comments

Comments
 (0)