Commit 90dd4de
committed
fix(grammar): stop the Swift scanner shifting past the width of an int
The Swift scanner keeps a 64-bit mask of the symbols that suppress a
match -- the rule that stops `try!` emitting its `!` as a separate
token. It tests one bit per candidate:
uint64_t suppressing_symbols = OP_SYMBOL_SUPPRESSOR[full_match];
for (uint64_t suppressor = 0; suppressor < TOKEN_COUNT; suppressor++) {
if (!(suppressing_symbols & 1 << suppressor)) {
The mask is uint64_t but the literal `1` is an int, so the shift is an
int shift. TOKEN_COUNT is larger than 32, so once suppressor reaches 31
the shift runs past the width of the type. That is undefined behavior,
and every bit above 31 is tested against a value the standard does not
define.
Nothing caught it because no test reached the suppressor path until
this branch added one: a Swift URL is force-unwrapped, `URL(string:
"...")!`, and the trailing `!` is exactly the case the suppressor list
exists for.
UBSan reports it as:
scanner.c:514:47: runtime error: left shift of 1 by 31 places
cannot be represented in type 'int'
The Windows CLANGARM64 leg runs UBSan in trap mode, which turns the
same shift into an illegal-instruction trap rather than a message, so
the new test would take that leg down.
`1ULL` makes the literal as wide as the mask it is tested against.
Refs #1892
Signed-off-by: Joshua Richter <jrichter5781@gmail.com>1 parent 1f5ecb5 commit 90dd4de
1 file changed
Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments