[Lldb-commits] [lldb] [lldb] Fix heap-buffer-overflow in tree-sitter-swift scanner state (PR #224001)
Yao Qi via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 16 05:54:25 PDT 2026
https://github.com/qiyao created https://github.com/llvm/llvm-project/pull/224001
Running the `HighlighterTests` unit test under AddressSanitizer aborts
on every Swift test case, for example `SwiftComments`:
```
==69424==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000008070 at pc 0x000116a1f36c bp 0x00016d07c3c0 sp 0x00016d07c3b8
READ of size 4 at 0x602000008070 thread T0
#0 0x000116a1f368 in eat_raw_str_part scanner.c:700
#1 0x000116a1b5f4 in tree_sitter_swift_external_scanner_scan scanner.c:858
#2 0x00012cc77420 in ts_parser_parse
#3 0x00012cc79afc in ts_parser_parse_string
#4 0x00010a3536a4 in lldb_private::TreeSitterHighlighter::Highlight(...)
0x602000008071 is located 0 bytes after 1-byte region [0x602000008070,0x602000008071)
allocated by thread T0 here:
#0 0x00012d68d560 in calloc
#1 0x00012cc763b8 in ts_parser_parse
#2 0x00012cc79afc in ts_parser_parse_string
```
`eat_raw_str_part` reads `state->ongoing_raw_str_hash_count` as its
first statement, a 4 byte field, but the scanner state was allocated
with:
```
void *tree_sitter_swift_external_scanner_create() {
return calloc(0, sizeof(struct ScannerState));
}
```
`calloc` with an element count of 0 has no obligation to reserve room
for `sizeof(struct ScannerState)`, so it works by accident, but is
found by ASAN.
Fix it by allocating one instance, matching the Rust scanner and the
struct's actual use as a single persistent state object across calls.
The existing `HighlighterTest.Swift*` tests already exercise this path
end to end and catch the regression under AddressSanitizer; no new
test is needed.
>From c6fc26dfbf4483f05e9de81cb21e09d326cab4d0 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao_qi at apple.com>
Date: Wed, 16 Sep 2026 11:01:58 +0100
Subject: [PATCH] [lldb] Fix heap-buffer-overflow in tree-sitter-swift scanner
state
Running the `HighlighterTests` unit test under AddressSanitizer aborts
on every Swift test case, for example `SwiftComments`:
```
==69424==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000008070 at pc 0x000116a1f36c bp 0x00016d07c3c0 sp 0x00016d07c3b8
READ of size 4 at 0x602000008070 thread T0
#0 0x000116a1f368 in eat_raw_str_part scanner.c:700
#1 0x000116a1b5f4 in tree_sitter_swift_external_scanner_scan scanner.c:858
#2 0x00012cc77420 in ts_parser_parse
#3 0x00012cc79afc in ts_parser_parse_string
#4 0x00010a3536a4 in lldb_private::TreeSitterHighlighter::Highlight(...)
0x602000008071 is located 0 bytes after 1-byte region [0x602000008070,0x602000008071)
allocated by thread T0 here:
#0 0x00012d68d560 in calloc
#1 0x00012cc763b8 in ts_parser_parse
#2 0x00012cc79afc in ts_parser_parse_string
```
`eat_raw_str_part` reads `state->ongoing_raw_str_hash_count` as its
first statement, a 4 byte field, but the scanner state was allocated
with:
```
void *tree_sitter_swift_external_scanner_create() {
return calloc(0, sizeof(struct ScannerState));
}
```
`calloc` with an element count of 0 has no obligation to reserve room
for `sizeof(struct ScannerState)`, so it works by accident, but is
found by ASAN.
Fix it by allocating one instance, matching the Rust scanner and the
struct's actual use as a single persistent state object across calls.
The existing `HighlighterTest.Swift*` tests already exercise this path
end to end and catch the regression under AddressSanitizer; no new
test is needed.
---
.../Highlighter/TreeSitter/Swift/tree-sitter-swift/scanner.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/Highlighter/TreeSitter/Swift/tree-sitter-swift/scanner.c b/lldb/source/Plugins/Highlighter/TreeSitter/Swift/tree-sitter-swift/scanner.c
index dcb6bf802f45c..3148218427c8c 100644
--- a/lldb/source/Plugins/Highlighter/TreeSitter/Swift/tree-sitter-swift/scanner.c
+++ b/lldb/source/Plugins/Highlighter/TreeSitter/Swift/tree-sitter-swift/scanner.c
@@ -188,7 +188,7 @@ struct ScannerState {
};
void *tree_sitter_swift_external_scanner_create() {
- return calloc(0, sizeof(struct ScannerState));
+ return calloc(1, sizeof(struct ScannerState));
}
void tree_sitter_swift_external_scanner_destroy(void *payload) {
More information about the lldb-commits
mailing list