Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to sem are documented in this file.

## [Unreleased]

### Fixed

- **Building a graph over Svelte components no longer crashes (SIGSEGV) on Linux/glibc.** `sem graph`/`context`/`orient` over `.svelte` files deterministically exited 139 from an invalid free in the `tree-sitter-htmlx-svelte` 0.1.8 grammar's scanner, hit during parallel graph construction (macOS's allocator tolerated the bad free, so it only showed on Linux). Bumped the grammar to 0.1.16, which carries the scanner fixes; the existing version constraint already permitted it, so this is a lock-only dependency update. Added a parallel-Svelte-graph regression test. Thanks @XF-FW for the exhaustive isolation and the verified fix (#471).

## [0.21.0] - 2026-07-10

### Added
Expand Down
4 changes: 2 additions & 2 deletions crates/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions crates/sem-core/tests/graph_accuracy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,73 @@ fn graph_accuracy_rust() {
);
assert!(tp > 0, "Should find at least some expected edges");
}

/// Regression for issue #471: building a graph over multiple Svelte components
/// in parallel triggered a SIGSEGV (invalid free) in the
/// tree-sitter-htmlx-svelte 0.1.8 grammar's scanner on Linux/glibc. Fixed by
/// bumping the grammar to 0.1.16. On macOS the bad free was tolerated by the
/// allocator, so this only fails on Linux/glibc CI; everywhere it at least
/// exercises the parallel Svelte parse path that used to crash.
#[test]
fn graph_svelte_parallel_no_crash_issue_471() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();

for args in [
vec!["init"],
vec!["config", "user.email", "test@test.com"],
vec!["config", "user.name", "Test"],
] {
std::process::Command::new("git")
.args(&args)
.current_dir(root)
.output()
.unwrap();
}

// Enough components that the parallel (rayon) graph build parses several
// .svelte files concurrently, which is where the grammar crashed.
let component = r#"<script lang="ts">
let count = 0;
function handleLogoClick() {
count += 1;
console.log("clicked", count);
}
</script>

<button on:click={handleLogoClick}>
clicked {count} times
</button>

<style>
button { color: blue; }
</style>
"#;
let mut files = Vec::new();
for i in 0..12 {
let name = format!("Component{i}.svelte");
std::fs::write(root.join(&name), component).unwrap();
files.push(name);
}

std::process::Command::new("git")
.args(["add", "."])
.current_dir(root)
.output()
.unwrap();
std::process::Command::new("git")
.args(["commit", "-m", "init"])
.current_dir(root)
.output()
.unwrap();

let registry = create_default_registry();
// Reaching past this call at all means no SIGSEGV during parallel parsing.
let (graph, _) = EntityGraph::build(root, &files, &registry);

// Sanity: the components were actually parsed, not silently skipped.
assert!(
graph.entities.values().any(|e| e.name == "handleLogoClick"),
"expected handleLogoClick entity from parsed .svelte components"
);
}
Loading