Skip to content

Commit 2eb8a58

Browse files
ashketchumwasherearcady-lunarg
authored andcommitted
preprocessor: guard elseSeen/ifdepth against negative elsetracker
A malformed #if expression (e.g. '#if %%%') causes eval() to return err=true. CPPif increments ifdepth and elsetracker but does not invoke CPPelse, leaving the preprocessor tracking a phantom conditional block. Subsequent excess #endif directives are consumed inside CPPelse: the depth > 0 path at Pp.cpp:328 runs --ifdepth without any guard, driving ifdepth negative. Once ifdepth < 0 the 'if (ifdepth == 0)' guard in readCPPline is permanently bypassed (only catches exactly zero). Every further #endif then executes elseSeen[elsetracker] = false with elsetracker running arbitrarily negative, writing zero-bytes backward through TPpContext into the lastLineTokenLocs vector control block, corrupting its internal pointers and causing a deterministic SEGV. Fix with three one-line guards: - Pp.cpp:319 (CPPelse): check elsetracker >= 0 before writing elseSeen - Pp.cpp:328 (CPPelse depth>0 path): check ifdepth > 0 before decrement - Pp.cpp:1011 (readCPPline): check elsetracker >= 0 before writing elseSeen Add test preprocessor.elseseen.oob.vert that reproduces the crash path: a bad #if desynchronises the counters, excess #endifs then drive elsetracker to -10. With the fix all excess #endifs produce 'mismatched statements' errors cleanly; without it the process crashes.
1 parent a899a43 commit 2eb8a58

5 files changed

Lines changed: 64 additions & 3 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
ERROR: 0:18: 'preprocessor evaluation' : bad expression
2+
ERROR: 0:18: '#if' : unexpected tokens following directive
3+
ERROR: 0:31: '#endif' : mismatched statements
4+
ERROR: 0:32: '#endif' : mismatched statements
5+
ERROR: 0:33: '#endif' : mismatched statements
6+
ERROR: 0:34: '#endif' : mismatched statements
7+
ERROR: 0:35: '#endif' : mismatched statements
8+
ERROR: 0:36: '#endif' : mismatched statements
9+
ERROR: 0:37: '#endif' : mismatched statements
10+
ERROR: 0:38: '#endif' : mismatched statements
11+
ERROR: 0:39: '#endif' : mismatched statements
12+
ERROR: 0:40: '#endif' : mismatched statements
13+
ERROR: 12 compilation errors. No code generated.
14+
15+

Test/baseResults/preprocessor.elseseen.oob.vert.out

Whitespace-only changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Test: guard against elseSeen[elsetracker] OOB write when elsetracker < 0.
2+
//
3+
// A malformed #if expression causes eval() to return err=true; CPPif increments
4+
// ifdepth/elsetracker but skips the branch scan. The subsequent nested
5+
// #if 0 / #endif block enters CPPelse with depth > 0, driving ifdepth negative
6+
// via the unguarded --ifdepth at Pp.cpp:328. Once ifdepth < 0 the
7+
// readCPPline guard (if (ifdepth == 0)) is permanently bypassed, and every
8+
// further #endif decrements elsetracker without bound.
9+
//
10+
// Without the fix, elseSeen[elsetracker] writes 0x00 backward through TPpContext
11+
// into lastLineTokenLocs, crashing in scanToken (PpContext.h:384).
12+
// With the fix, both write sites check elsetracker >= 0, and the unguarded
13+
// --ifdepth is protected by if (ifdepth > 0).
14+
15+
#version 450
16+
17+
// Step 1: bad expression desynchronises ifdepth and elsetracker.
18+
#if %%%
19+
#endif
20+
21+
// Step 2: nested block enters CPPelse depth>0 path, ifdepth goes negative.
22+
#if 0
23+
#if 1
24+
#if 1
25+
#endif
26+
#endif
27+
#endif
28+
29+
// Step 3: excess #endifs hit readCPPline with ifdepth < 0; without the
30+
// elsetracker >= 0 guard they would write OOB into the struct.
31+
#endif
32+
#endif
33+
#endif
34+
#endif
35+
#endif
36+
#endif
37+
#endif
38+
#endif
39+
#endif
40+
#endif
41+
42+
void main() {}

glslang/MachineIndependent/preprocessor/Pp.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
316316
}
317317
} else if (nextAtom == PpAtomEndif) {
318318
token = extraTokenCheck(nextAtom, ppToken, scanToken(ppToken));
319-
elseSeen[elsetracker] = false;
319+
if (elsetracker >= 0)
320+
elseSeen[elsetracker] = false;
320321
--elsetracker;
321322
if (depth == 0) {
322323
// found the #endif we are looking for
@@ -325,7 +326,8 @@ int TPpContext::CPPelse(int matchelse, TPpToken* ppToken)
325326
break;
326327
}
327328
--depth;
328-
--ifdepth;
329+
if (ifdepth > 0)
330+
--ifdepth;
329331
} else if (matchelse && depth == 0) {
330332
if (nextAtom == PpAtomElse) {
331333
elseSeen[elsetracker] = true;
@@ -1008,7 +1010,8 @@ int TPpContext::readCPPline(TPpToken* ppToken)
10081010
if (ifdepth == 0)
10091011
parseContext.ppError(ppToken->loc, "mismatched statements", "#endif", "");
10101012
else {
1011-
elseSeen[elsetracker] = false;
1013+
if (elsetracker >= 0)
1014+
elseSeen[elsetracker] = false;
10121015
--elsetracker;
10131016
--ifdepth;
10141017
}

gtests/Pp.FromFile.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ INSTANTIATE_TEST_SUITE_P(
7272
"preprocess.inactive_stringify.vert",
7373
"preprocessor.paste_stringify.vert",
7474
"preprocessor.stringify_invalid.vert",
75+
"preprocessor.elseseen.oob.vert",
7576
})),
7677
FileNameAsCustomTestSuffix
7778
);

0 commit comments

Comments
 (0)