Version
Built from source at ae5de7fe (main), release line v0.10.8
Platform
Windows (x64)
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
The vendored Swift grammar scanner shifts a literal 1 past the width of its own type in
two places. Both are undefined behaviour.
| Line |
Code |
Left operand |
Shift count |
State |
| 514 |
1 << suppressor |
int, 32 bits everywhere |
reaches 32 |
fixed in #1977 |
| 131 |
1UL << FAKE_TRY_BANG |
unsigned long, 32 bits on Windows |
exactly 32 |
open |
Both live in internal/cbm/vendored/grammars/swift/scanner.c.
For line 514, TOKEN_COUNT is 33, so the loop counter reaches 32. The mask being tested
is a uint64_t, which makes the intent unambiguous.
For line 131, FAKE_TRY_BANG is 32 — I counted the TokenType enum in that file: 33
entries, and FAKE_TRY_BANG is the last. On Linux and macOS unsigned long is 64 bits
and the shift is fine. On Windows it is 32 bits, so the shift count equals the full width
of the type.
I expected the entry to produce 1 << 32 as a 64-bit value. On Windows it produces
whatever the compiler decides an undefined shift produces.
Neither of these is only my reading of the standard. Upstream
alex-pinkus/tree-sitter-swift fixed both independently:
- line 514 in
fb63a7004f07 (2026-04-06), "Fix UB in eat_operators"
- line 131 in
6ab8d1d74ebd (2026-08-10), "Fix undefined 32-bit shift in OP_SYMBOL_SUPPRESSOR on LLP64 targets"
Both changes are one token each: 1 to 1ULL, and 1UL to 1ULL.
MANIFEST.md pins the Swift grammar at 8abb3e8b3325, dated 2026-03-20. Both upstream
fixes landed after that pin. Our copy is a faithful vendor rather than a local edit — I
checked it byte-identical to upstream at that commit.
Why nothing here catches it. This is the part I think is worth your time, because it
explains why Windows CI has stayed green:
- Line 131 is a compile-time constant expression, so no sanitizer sees it at run time.
Makefile.cbm:719 compiles every vendored grammar with -w, which switches off all
warnings — including -Wshift-count-overflow, the one diagnostic that names this exact
defect. The comment on line 718 gives the reason: "upstream code has warnings."
CLANG64 on windows-latest is in CORE_WIN (.github/workflows/_test.yml:63), so
the affected platform is built on every pull request and reports nothing.
A suggestion, not part of this report. Turning on just -Wshift-count-overflow for
vendored grammars — one narrow warning, not -Wall -Werror — would catch this class
across all 104 vendored scanners without reintroducing the upstream warning noise that
-w exists to suppress. I have not tried it and I am not proposing it here. Happy to
open a separate issue if you want it explored.
Reproduction
I have no Windows machine, so I have no runtime reproduction on the affected platform,
and I would rather say that than invent one. Two honest substitutes.
1. The mechanism, which you can run anywhere. unsigned int is 32 bits on every
target, so it stands in for Windows' unsigned long:
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint64_t m = 1u << 32; /* same shape as scanner.c:131 on Windows */
printf("%llu\n", (unsigned long long)m);
}
With warnings on, the compiler names the defect:
repro.c:4:21: warning: shift count >= width of type [-Wshift-count-overflow]
4 | uint64_t m = 1u << 32;
| ^ ~~
Compiled with -w, as the grammar build does, that warning disappears and the program
runs. The result is not merely wrong — it is unstable. Three runs of one binary on Apple
clang 21.0.0, arm64:
4338156640
4364321888
4377183328
At -O2 it settles on a different value again (8447164672). m is never actually
assigned; the compiler treats the shift as poison and leaves stack garbage behind. Writing
the same line correctly as (uint64_t)1 << 32 prints 4294967296 every time.
That is the mechanism, on my platform, with unsigned int standing in. It is not a
measurement of what Windows does with 1UL << 32 — I have not run that, and I am not
claiming the two produce the same value.
2. How to confirm the real effect, if you have a Windows box. Index a Swift file
containing a force-unwrap or try! on Windows and on Linux, then compare the extracted
tokens. OP_SYMBOL_SUPPRESSOR[BANG] is what stops try! emitting its ! as a token of
its own. If that entry is wrong on Windows, Swift extraction differs there and nothing
currently fails to say so.
What I am claiming, and what I am not. Established: the expression is undefined, its
location, and that upstream judged both lines worth fixing. Not established: that a
symptom is visible in extracted output today. I did not want to overstate a bug I found by
reading rather than by running.
Logs
Not applicable — this is a source-level defect found by inspection, not a runtime failure.
The compiler diagnostic that would normally appear is suppressed by -w on grammar builds.
Diagnostics trajectory (memory / performance / leak issues)
Not applicable — not a memory or performance issue.
Project scale (if relevant)
Not relevant — the defect is in a vendored grammar, independent of project size.
Confirmations
Version
Built from source at
ae5de7fe(main), release line v0.10.8Platform
Windows (x64)
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
The vendored Swift grammar scanner shifts a literal
1past the width of its own type intwo places. Both are undefined behaviour.
1 << suppressorint, 32 bits everywhere1UL << FAKE_TRY_BANGunsigned long, 32 bits on WindowsBoth live in
internal/cbm/vendored/grammars/swift/scanner.c.For line 514,
TOKEN_COUNTis 33, so the loop counter reaches 32. The mask being testedis a
uint64_t, which makes the intent unambiguous.For line 131,
FAKE_TRY_BANGis 32 — I counted theTokenTypeenum in that file: 33entries, and
FAKE_TRY_BANGis the last. On Linux and macOSunsigned longis 64 bitsand the shift is fine. On Windows it is 32 bits, so the shift count equals the full width
of the type.
I expected the entry to produce
1 << 32as a 64-bit value. On Windows it produceswhatever the compiler decides an undefined shift produces.
Neither of these is only my reading of the standard. Upstream
alex-pinkus/tree-sitter-swiftfixed both independently:fb63a7004f07(2026-04-06), "Fix UB in eat_operators"6ab8d1d74ebd(2026-08-10), "Fix undefined 32-bit shift in OP_SYMBOL_SUPPRESSOR on LLP64 targets"Both changes are one token each:
1to1ULL, and1ULto1ULL.MANIFEST.mdpins the Swift grammar at8abb3e8b3325, dated 2026-03-20. Both upstreamfixes landed after that pin. Our copy is a faithful vendor rather than a local edit — I
checked it byte-identical to upstream at that commit.
Why nothing here catches it. This is the part I think is worth your time, because it
explains why Windows CI has stayed green:
Makefile.cbm:719compiles every vendored grammar with-w, which switches off allwarnings — including
-Wshift-count-overflow, the one diagnostic that names this exactdefect. The comment on line 718 gives the reason: "upstream code has warnings."
CLANG64onwindows-latestis inCORE_WIN(.github/workflows/_test.yml:63), sothe affected platform is built on every pull request and reports nothing.
Reproduction
I have no Windows machine, so I have no runtime reproduction on the affected platform,
and I would rather say that than invent one. Two honest substitutes.
1. The mechanism, which you can run anywhere.
unsigned intis 32 bits on everytarget, so it stands in for Windows'
unsigned long:With warnings on, the compiler names the defect:
Compiled with
-w, as the grammar build does, that warning disappears and the programruns. The result is not merely wrong — it is unstable. Three runs of one binary on Apple
clang 21.0.0, arm64:
At
-O2it settles on a different value again (8447164672).mis never actuallyassigned; the compiler treats the shift as poison and leaves stack garbage behind. Writing
the same line correctly as
(uint64_t)1 << 32prints4294967296every time.That is the mechanism, on my platform, with
unsigned intstanding in. It is not ameasurement of what Windows does with
1UL << 32— I have not run that, and I am notclaiming the two produce the same value.
2. How to confirm the real effect, if you have a Windows box. Index a Swift file
containing a force-unwrap or
try!on Windows and on Linux, then compare the extractedtokens.
OP_SYMBOL_SUPPRESSOR[BANG]is what stopstry!emitting its!as a token ofits own. If that entry is wrong on Windows, Swift extraction differs there and nothing
currently fails to say so.
What I am claiming, and what I am not. Established: the expression is undefined, its
location, and that upstream judged both lines worth fixing. Not established: that a
symptom is visible in extracted output today. I did not want to overstate a bug I found by
reading rather than by running.
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
Not relevant — the defect is in a vendored grammar, independent of project size.
Confirmations