Repository navigation
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Summary
The single-file route of semaprax build has none of the fresh-destination guards the project route enforces:
build <file>.spx --target native -o <existing file>silently overwrites the file with the executable and exits 0.-opointing at the.spxsource itself replaces the source with a Mach-O binary.build <file>.spx --target web|wasm -o <existing non-empty directory>writes into the directory, overwriting same-named files (index.html,package.json, …) and exits 0. Two concurrent single-file web builds into one-oboth "succeed".- Ordinary
-opath errors (missing parent, read-only parent, trailing slash) surface as rawld:/clang:linker output underSPX-B102instead of theSPX-I301/SPX-I307diagnostics the project route emits before compiling.
The project route refuses all of these (SPX-I307 … destination already exists), and docs/PROJECT-MANIFEST-V1.md ("CLI and artifacts") promises a native build never clobbers an existing file. Identical -o spellings therefore behave oppositely depending on whether the input is a file or a manifest. This is data loss on an agent-facing command.
Observed on semaprax 0.3.0 built from main at 5c6e7a4b.
Reproducers
cp examples/calculator.spx calc.spx
echo precious > victim
semaprax build calc.spx --target native -o victim; echo "rc=$?"
# built native executable victim rc=0
file victim # Mach-O 64-bit executable arm64
semaprax build calc.spx --target native -o calc.spx; echo "rc=$?"
# built native executable calc.spx rc=0
semaprax check calc.spx # error[SPX-I001]: cannot read calc.spx: stream did not contain valid UTF-8
mkdir ne; echo mine > ne/index.html; echo keep > ne/keep.txt
semaprax build examples/calculator.spx --target web -o ne; echo "rc=$?"
# built web package ne rc=0 ne/index.html replaced, ne/keep.txt kept
# project route, for comparison
echo x > v2; semaprax build examples/calculator-project --target native -o v2
# error[SPX-I307]: Project v1 native executable destination already exists: v2 rc=1Root cause
src/cli_driver.rs::build_source→codegen::build→src/codegen/native_emit/mod.rs~line 2174write_and_compile_c_with_runnerpasses-o <output>straight to clang, which truncates and overwrites.src/wasm.rs~line 1678build_webcallsstd::fs::create_dir_all(output)and then unconditionallyfs::writes each package file.- The project route's guard lives in
src/project/mod.rs~line 789 (SPX-I307) and the scalar-export package has its own fresh-destination check insrc/wasm.rs~2643-2690; neither is applied toBuildInput::Source.
Suggested fix
- Apply the same create-new contract to the single-file route: refuse if the destination exists (
symlink_metadata), compile/link into a temporary sibling in the destination's parent, then rename with create-new semantics so concurrent builds cannot both succeed. Refuse-othat resolves to any input source path explicitly. - For web/wasm, use
fs::create_dir(create-new) or reuse the scalar-export package's fresh-destination check. - Pre-check the parent directory (exists, writable, not a file) and emit
SPX-I301/SPX-I307before invoking clang, so raw linker text never reaches the user. - Regression tests in the harness that owns single-file build (
tests/compiler.rsmodule tree): existing file, existing directory, the source path itself, missing parent, read-only parent; assert exit 1, the SPX code, and that the pre-existing bytes are untouched. - Document the contract in
docs/CLI-GUIDE.md("build" section) andCHANGELOG.md.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity