Skip to content

Commit 620613e

Browse files
authored
Merge pull request #1986 from CaptainMittens/fix/swift-scanner-try-bang-shift
fix(grammar): stop the Swift try-bang entry shifting past its own type
2 parents aefd2a1 + e820409 commit 620613e

4 files changed

Lines changed: 27 additions & 5 deletions

File tree

internal/cbm/vendored/grammars/MANIFEST.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,17 @@ Guarded by the `contract_all_grammars_in_graph` graph-breadth test in
7777

7878
The grammars below carry a small local patch to their vendored sources, on
7979
top of the pinned upstream commit recorded in the vendoring table below.
80-
Re-vendoring from upstream must re-apply these.
80+
Re-vendoring from upstream must re-apply these, unless the reason column
81+
names an upstream commit that already carries the change — then drop the
82+
row instead.
8183

8284
| grammar | location | patch | reason |
8385
|---|---|---|---|
8486
| crystal | `crystal/scanner.c`, serialize | guard `memcpy(&buffer[offset], state->literals.contents, literal_content_size)` with `if (literal_content_size > 0)` | UBSan: zero-length `memcpy` with a NULL/0-size source on the empty-state serialize round-trip (formal UB, harmless) |
8587
| rescript | `rescript/scanner.c`, deserialize | guard `memcpy(state, buffer, n_bytes)` with `if (n_bytes > 0)` | UBSan: zero-length `memcpy` with a NULL `buffer` / `n_bytes == 0` on empty-state deserialize (formal UB, harmless). The sibling serialize copies a fixed `sizeof(ScannerState)` (always > 0, non-NULL src) and needs no guard. |
8688
| purescript | `purescript/scanner.c`, serialize | guard `memcpy(buffer, indents->data, to_copy)` with `if (to_copy > 0)` | UBSan: zero-length `memcpy` with a NULL/0-size source when the indent vector is empty (formal UB, harmless) |
8789
| plsql | `plsql/parser.c`, include | `#include <tree_sitter/parser.h>``#include "tree_sitter/parser.h"` | The older ABI-14 generator emits angle brackets; every other vendored grammar uses the quoted form, which resolves the per-grammar `tree_sitter/` header from the including file's directory |
90+
| swift | `swift/scanner.c`, `OP_SYMBOL_SUPPRESSOR` + `eat_operators` | `1UL <<` / `1 <<``1ULL <<` | UBSan: `1 << suppressor` shifts an `int` by up to `TOKEN_COUNT` bits, undefined once the index reaches 31, while the mask it feeds is `uint64_t`. `1UL << FAKE_TRY_BANG` is the same defect on Windows, where `unsigned long` is 32 bits and `FAKE_TRY_BANG` is 32; the CLANGARM64 leg runs UBSan in trap mode, so there it is an illegal instruction rather than a log line. Upstream already carries both changes: `fb63a7004f07` (2026-04-06, upstream #558) for `eat_operators`, `6ab8d1d74ebd` (2026-08-10) for the `OP_SYMBOL_SUPPRESSOR` entry. Our pin `8abb3e8b3325` (2026-03-20) predates both, so this is a backport rather than a local invention — a re-vendor past 2026-08-10 should delete this row, not re-apply it |
8891

8992
## Vendored from verified upstream
9093

internal/cbm/vendored/grammars/swift/scanner.c

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/vendored-checksums.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ c5cfb43042b6b72045f4ba997834d0a7786d2793d91680868b5815b39f14fc78 internal/cbm/v
55
b29c1c9fb7cc82f58c84b376df1297d6e2737a1d655fd356db0859e3c29c2fea internal/cbm/vendored/common/tree_sitter/alloc.h
66
31e60a1bff6f715afacce03b5b70efe42b58371b4f9595dd4af52a577ff9608c internal/cbm/vendored/common/tree_sitter/array.h
77
180b893c8734778fd32f372dfbc27bd6ad1cd2221f26150b31256ff6716320d2 internal/cbm/vendored/common/tree_sitter/parser.h
8-
e1233d81f21d868b8f2d9e8fca10e15f2ec3ae4db4a7ba0301161cc011deef65 internal/cbm/vendored/grammars/MANIFEST.md
8+
00a84162eb34fb58bcdd38c08922d4fea4c87b7c2219dd64b773dd15ba18de71 internal/cbm/vendored/grammars/MANIFEST.md
99
ad8425038de519f8c4e3e9339feebf99dfad8a6002dcf79227d91402780a32cc internal/cbm/vendored/grammars/ada/LICENSE
1010
02805ec13939b749c891567be36bf024b09034e04c80683a1ae667272458d549 internal/cbm/vendored/grammars/ada/parser.c
1111
115a75d000bef9c70c4de7dfbb7f2a80b90cbb14ba265056dc7abb1ef3b9b6db internal/cbm/vendored/grammars/ada/tree_sitter/alloc.h
@@ -791,7 +791,7 @@ c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 internal/cbm/v
791791
2db740ea1be6b71014d2be1385491f01bf2d15b607e61c5b30b4128535efe68a internal/cbm/vendored/grammars/sway/tree_sitter/parser.h
792792
3533cec129bb4bba015c0d61d86dd7c3b7e82110e4d2ff7837a01eff5bad5ccc internal/cbm/vendored/grammars/swift/LICENSE
793793
93e6b39fc5b16ef9d5869862ec8d56380a838355c362481942942d59ca666de2 internal/cbm/vendored/grammars/swift/parser.c
794-
b835c1ded068e902944fe82c3770b9dcf85f67dcaab8fbf772f1606007da7373 internal/cbm/vendored/grammars/swift/scanner.c
794+
8a14f26c9011a02298a076674461beb48625a4ca7cea4a0f63947930d93631fd internal/cbm/vendored/grammars/swift/scanner.c
795795
b29c1c9fb7cc82f58c84b376df1297d6e2737a1d655fd356db0859e3c29c2fea internal/cbm/vendored/grammars/swift/tree_sitter/alloc.h
796796
5bdf6ed1a78e3409fd443e085ca967a64c188a5d082aaf7f819bccd53a471c94 internal/cbm/vendored/grammars/swift/tree_sitter/array.h
797797
a1f6ef161fbaf48a0e10fca90ef5290a062462b307b3898aa562993853b9f80a internal/cbm/vendored/grammars/swift/tree_sitter/parser.h

tests/test_extraction.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,24 @@ TEST(swift_chained_call) {
18101810
PASS();
18111811
}
18121812

1813+
/* A Swift force-unwrap is the one thing that reaches the scanner's suppressor
1814+
* path -- the rule that stops `try!` emitting its `!` as a token of its own.
1815+
* That path shifted an int by up to TOKEN_COUNT bits, which runs past the
1816+
* width of the type once the index reaches 31.
1817+
*
1818+
* This test cannot go red here. The normal test build prints the UBSan
1819+
* message and carries on, which is why the bug survived. The Windows
1820+
* CLANGARM64 leg runs UBSan in trap mode, where the same shift is an
1821+
* illegal-instruction crash, so parsing this file at all is the check. */
1822+
TEST(swift_force_unwrap_scanner_shift) {
1823+
CBMFileResult *r =
1824+
extract("func load() { let u = cached! }\n", CBM_LANG_SWIFT, "t", "Load.swift");
1825+
ASSERT_NOT_NULL(r);
1826+
ASSERT_FALSE(r->has_error);
1827+
cbm_free_result(r);
1828+
PASS();
1829+
}
1830+
18131831
/* --- Objective-C --- */
18141832
TEST(objc_interface) {
18151833
CBMFileResult *r =
@@ -6661,6 +6679,7 @@ SUITE(extraction) {
66616679
RUN_TEST(swift_method_call);
66626680
RUN_TEST(swift_constructor_call);
66636681
RUN_TEST(swift_chained_call);
6682+
RUN_TEST(swift_force_unwrap_scanner_shift);
66646683
RUN_TEST(objc_interface);
66656684
RUN_TEST(objc_implementation);
66666685
RUN_TEST(dart_top_level_function);

0 commit comments

Comments
 (0)