fix: panic on assembler source manager mismatch#2987
fix: panic on assembler source manager mismatch#2987juan518munoz wants to merge 5 commits into0xMiden:mainfrom
Conversation
|
Automated check (CONTRIBUTING.md) Recommendations:
Next steps:
|
| // The source id exists, so file_line_col should succeed. If it doesn't, the | ||
| // span's byte offsets are out of bounds for the file at that source id, which | ||
| // indicates the module was parsed with a different source manager. | ||
| let file_line_col = source_manager.file_line_col(span).map_err(|err| { |
There was a problem hiding this comment.
Could this still attach debug info to the wrong file when the assembler's manager has the same SourceId and that file is long enough? SourceId is only local to one manager, so get plus file_line_col proves the offset fits some file in this manager, but not that the span came from it. In that case the mismatch would still slip through as wrong debug metadata.
huitseeker
left a comment
There was a problem hiding this comment.
Please fix the false-negative.
|
Fixing the false negative required a broader change. As The proposed fix in 1480dee uses |
| /// An alias for creating the default, but empty, `#kernel` [Module]. | ||
| pub fn new_kernel() -> Self { | ||
| Self::new(ModuleKind::Kernel, Path::kernel_path()) | ||
| Self::new(ModuleKind::Kernel, Path::kernel_path(), Self::empty_source_file()) |
There was a problem hiding this comment.
I think this regresses in-memory AST modules.
new_kernel() and new_executable() now attach a synthetic SourceFile, but later register_procedure_debug_info() treats any file not owned by the assembler's SourceManager as an error.
I reproduced this with a programmatically built module containing one nop procedure: Assembler::new(sm).assemble_library([module]) now returns source manager mismatch instead of just skipping debug info.
Could we represent 'no backing source file' as None here?
There was a problem hiding this comment.
Forgot to reply here as well, but it's also been handled as of 713e931
| self.debug_info.register_procedure_debug_info( | ||
| &procedure, | ||
| self.source_manager.as_ref(), | ||
| module_source_file.as_deref(), |
There was a problem hiding this comment.
The source-manager check lands too late here.
compile_procedure() already uses self.source_manager for instruction spans and diagnostics before we reach register_procedure_debug_info(), so a mismatched module can still take the wrong source path first.
I reproduced that with a module parsed in one manager and assembled in another using loc_loadw_be.2: formatting the compile error panicked in SourceFile::location. We should reject the module before lowering starts.
There was a problem hiding this comment.
Moved the source-manager check to linking time so it covers this.
|
Thanks for the re-review @huitseeker, PR is ready to be reviewed again. I was wondering if it would be preferable to point this to either |
huitseeker
left a comment
There was a problem hiding this comment.
LGTM, thanks for fixing this!
2528505 to
e537d12
Compare
|
Thanks for the review, I've rebased into EDIT: As a second though, this has breaking changes (public API change), so it may be better suited for |
|
If this is the only commit that's going to a new patch version, and a maintainer of this repo agrees, maybe you can bump the crate version here too. |
huitseeker
left a comment
There was a problem hiding this comment.
Reflecting @bitwalker 's review on #3007:
This PR makes some assumptions about how source files are related to modules which are incorrect, so I don't think it makes sense to merge it (or #2987).
I'm not sure this is even the correct way to handle this in general - if you've somehow gotten your source managers mixed up, you want to know exactly where that happened, and a panic is useful for that. If you instead silently drop the source locations, or try to bubble up an
Err, you'll lose valuable context about where the wires got crossed.IMO, this is really a documentation issue related to how
SourceManagerimpls need to be used, both from the caller perspective, and in terms of threading them through internals of the VM or other components.
| /// The source file from which this module was parsed, if any. | ||
| /// | ||
| /// This is `None` for programmatically-constructed modules (e.g. `new_kernel()`, | ||
| /// `new_executable()`) that have no backing source text. |
There was a problem hiding this comment.
Reflecting @bitwalker 's review on #3007 :
There are two issues with this:
- Programmatically-constructed modules can absolutely have a backing source file - it just means that the source language was not Miden Assembly (or that the AST was literally constructed by hand for a test, but that's not the important case).
- Source spans within a
Moduledo not have to come from the same source file, and in fact that is the common case when compiling from Rust source code currently.
huitseeker
left a comment
There was a problem hiding this comment.
As above and as reviewed by @bitwalker in #3007.
When a pre-parsed module is assembled using a different source manager than the one it was parsed with, the assembler used to panic during debug info registration because span byte offsets didn't match the resolved source file.
This PR replaces the panic with proper error handling: missing source ids are skipped silently, while out-of-bounds spans are surfaced as a compilation error with a descriptive message pointing to the source manager mismatch.
Closes #2986