-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SPARC - passing argument from C++ to Rust issue #86163
Comments
Sounds like an ABI definition issue (e.g. something is passed via a value while it should be passed via a pointer). Marking this as unsound, as instead of a pointer, this could be mangling a pointer or a reference. Can we see the disassembly for the calling side as well? Could you also try to produce a MCVE (a test case that does not rely on external crates?) by inlining the type definitions, etc. Also helpful would be a removal of the panics, e.g. by replacing them with |
Following is
And this is its disassembly (_ZN7mozilla2wr18DisplayListBuilder19PushStackingContextERKNS0_21StackingContextParamsERKNS0_4RectIfNS0_11LayoutPixelEEERKNS0_11RasterSpaceE):
And here is again my
And it's disassembly is:
|
Agreed looks like Rust's SPARCv9 64-bit ABI definition issue. In more detail, it seems to me Rust thinks the floating point registers are 64-bit, while they are still 32-bit in the processor [1]. The mismatch causes Rust function to read garbage when the argument is structure containing floats and it is passed by value. Here's a small test case, where C calls into Rust:
Expected output: Actual output: The disassembler shows:
That the caller passes arguments via %f0, %f1, %f2, %f3, %o2,
^ caller reads arguments from %f1, %f3, %f5, %f7 that are lower 32-bit parts of double precision (64-bit) floating point registers. So while Rust correctly interprets the structure members as f32, it seems it thinks they are passed in the aggregate (structure) as f64!? At the end Rust reads the second argument of function funkce from %i4 (skips 4x64-bits -> %i0, %i1, %i2, %i3), however, the caller has put it in %i2 (skipping 4x32 bits -> %i0, %i1 since all %i registers are 64-bit wide). The difference in how many input arguments are skipped by Rust and Gcc is another evidence that there's mismatch in size of floating point members of structure passed by value as first argument. Is the function is_homogenous_aggregate() in librustc_trans/cabi_sparc64.rs right place to look at to check if it correctly sets argument size? [1] section 5.1.4 in SPARC Architecture Manual, |
That function, or rather the file in its entirety is a correct place to look at, yes. Looking at the LLVM IR, this is the signature generated by Rust today: @funkce([4 x float] %0, i32 signext %i) unnamed_addr Whereas it really ought to be @funkce(float, float, float, float, i32) unnamed_addr or similar. It does seem that is_homogenous_aggregate is involved in at least some way, here. |
I guess that the same problem is also on SPARC Linux. @glaubitz can you please test above test case? |
On Linux, I'm getting:
|
Thanks for trying on Linux, that's the same issue. Rust function funkce() gets invalid arguments. The difference of arguments being 0 on Linux vs garbage on Solaris might be caused by something that used registers e.g. library initialization. |
Assigning priority as discussed in the Zulip thread of the Prioritization Working Group. @rustbot label -I-prioritize +P-high |
How can this be fixed? Where is relevant code doing this?
|
@nagisa any suggestion how to proceed with this issue? Where to look, what to try? Thanks! |
It sounds like Firefox will not work on SPARC anymore if this bug has not been fixed until the release of Firefox 93. |
If I understand it right, we need to modify: So that for aggregate data argument (structure with floats) are split into registers... |
Now Rust (--emit=llvm-ir ) for SPARC64 generates for the test case:
where Clang (-S -emit-llvm) for C test case equivalent does:
Clang SPARC64 ABI generation and usage of With my limited knowledge of Rust and its internals I was so far only able to come with below patch for sparc64.rs which generates:
It works for the test case and it works for the original Firefox bug: Problem is that now it uses Webrender (which I have never tested on SPARC) and Firefox shows window with nothing just black background. So it may be eventually some other SPARC Webrender issue. Not sure whether it's related but in console I see several occurrence of:
Any suggestions or comments are welcome! The patch for Rust 1.53.0 is.
|
Ok, the above fix doesn't fix all possibilities. Another occurrence is structure with doubles: |
fix sparc64 ABI for aggregates with floating point members Fixes rust-lang#86163
fix sparc64 ABI for aggregates with floating point members Fixes rust-lang#86163
This was originally reported as Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1714064
But now it seems to be rather Rust issue.
Unfortunately I wasn't able to reproduce it outside of Firefox yet:
C++ code calls
wr_dp_push_stacking_context()
with parameteraParams.mFilterDatas.Length()
which is zero (0):https://searchfox.org/mozilla-central/rev/79d73b4aff88dd4a0f06dd3789e1148c49b0de60/gfx/webrender_bindings/WebRenderAPI.cpp#1028
But Rust code gets instead of
0
some nonsense number (e.g. 133081200598864):https://searchfox.org/mozilla-central/rev/79d73b4aff88dd4a0f06dd3789e1148c49b0de60/gfx/webrender_bindings/src/bindings.rs#2455
I was able to limit the
wr_dp_push_stacking_context()
to just:And the problem is still there. But when I swap
bounds: LayoutRect
withfilter_count: usize
thenfilter_count
is passed correctly!LayoutRect
is quite complicated (to me):https://searchfox.org/mozilla-central/rev/79d73b4aff88dd4a0f06dd3789e1148c49b0de60/gfx/wr/webrender_api/src/units.rs#86
Important might be that it uses floating numbers!
Following is disassembled
wr_dp_push_stacking_context
function as defined above:The text was updated successfully, but these errors were encountered: