fix: resolve the input path against the root before making it virtual - #37
Merged
evolvedlight merged 2 commits intoSep 6, 2026
Merged
Conversation
A Typst virtual path only accepts forward slashes, and `VirtualPath::new` was handed the caller's path verbatim. On Windows an ordinary relative path such as `templates\letter.typ` therefore failed to convert, and the `unwrap` turned that into a panic inside `create_compiler`. That function is `extern "C"` and has no unwind guard, so the panic aborted the whole host process rather than failing the single call. Relative paths are now joined onto the project root and converted with `VirtualPath::virtualize`, which splits on the platform separator and does the root containment check itself. A path that genuinely escapes the root reports an error through the existing channel instead of panicking, and the manual UTF-8 check is no longer needed because `virtualize` covers it. The pack job gains a `cargo test` step. The Rust tests exercise the FFI entry points directly, which is the only place a panic crossing the boundary surfaces as a failing test rather than as a crashed test runner.
msallin
force-pushed
the
fix/input-path-virtualize
branch
from
September 4, 2026 11:49
c66c2df to
8dd77d6
Compare
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A Typst virtual path only accepts forward slashes.
SystemWorld::newhanded the caller's input path toVirtualPath::newverbatim and unwrapped the result, so on Windows an ordinary relative path such astemplates\letter.typfailed to convert and panicked.The panic happens inside
create_compiler, which isextern "C"and has no unwind guard. A panic cannot unwind out of anextern "C"frame, so the process aborts rather than the call failing. Running the new tests againstdevelop:For a service on Windows, or any layout that sets an explicit root and keeps templates in a subfolder, this terminates the host process on the first compile with no managed exception. A
..component in the path does the same.Change
Relative paths are joined onto the project root, then converted with
VirtualPath::virtualize, which splits on the platform separator and performs the root containment check itself. A path that escapes the root now returns an error through the existing channel instead of panicking.The manual
to_strUTF-8 check is dropped becausevirtualizereports that case asVirtualizeError::Utf8. The<main>unwrap becomes anexpectnaming the invariant.Every input the old code accepted resolves to the same virtual path. One input changes classification:
C:foo.typ(drive-relative, whichis_absolute()reports as false) used to produce aFileIdwhose segment wasC:foo.typ, and that id could never be read back becauserealizerejects a segment starting with a path prefix. It is now either a clean error or, when the root isC:, a working path.The
packjob gains acargo teststep. The Rust tests call the FFI entry points directly, and that is the only place a panic crossing the boundary shows up as a failing test rather than as a crashed test runner, so without it these regression tests would never run in CI.Known limitation
The root is matched against an absolute input path textually, so on Windows both have to use the same casing;
C:\Appas root withc:\app\letter.typas input is still reported as escaping. That behaviour is unchanged by this PR and is now noted in the release notes.This does not add an unwind guard to
create_compiler, and the message built atworld.rs:104is still discarded bylib.rs:142, which returns a bare null. Both are separate concerns.Tests
New
src/typst_core/tests/input_path.rscovers a nested relative path, a literaltemplates\letter.typon Windows, a path that leaves and re-enters the root, the equivalent absolute path, a relative path escaping the root, and an absolute path outside the root.Tests.cscovers the same cases through the managed API, including the common shape that passes no root at all.The Rust tests abort the test binary against
developand pass with the change.