@Scott Waye we're seeing "return pointer not aligned" failures in wit-bindgen CI again: https://github.com/bytecodealliance/wit-bindgen/actions/runs/9321335334/job/25669483093?pr=960. I think you tried to address that in https://github.com/bytecodealliance/wit-bindgen/commit/bcd136e583c51cb6819876478bdfd6bf96e1ea2d, but looks like maybe it needs more work?
I'm going to try to reproduce it and see if I can learn anything.
One of the tricks I used when working on the Java bindings was to allocate extra space in the return area (e.g. up to 8 extra bytes for 8-byte alignment) and then align the pointer explicitly before passing it to the host, i.e. so that it points to the first byte in the array that has the alignment we need. Shall we do the same for C#? If there's not a better fix on the horizon, I think we need to do something, because keeps popping up (e.g. here)
I'd like to try this locally first, give me until Monday please.
good news is that it does repro locally for me.
Is it possible to run the runtime tests with wasmtime? I.e. get a single wasm file so I can run wasmtime under lldb ?
You can find the components using e.g. find target/ -name *.component.wasm, but they all use custom worlds, so you can't treat them as wasi:cli commands and run them using wasmtime run, unfortunately.
However, you could edit the run_test_from_dir function in tests/runtime/main.rs and add a config.debug_info(true); line near the top. Then run e.g. cargo test --no-default-features --features csharp-naot, which will print the binary name used (e.g. target/debug/deps/runtime-448f003ef70967db). You can run that under LLDB.
From what I've heard there are issues with Wasmtime preserving debug info for components, but maybe those have been resolved?
thanks, I will have a try
hmmm, doesn't seem to want to resolve the breakpoints which is what you said was possibly still a problem
Yeah, that's what happened last time I tried it, unfortunately. @Ralph might know the status of debugging components.
The rust breakpoints work which might give a clue
I think this is telling me it has failed in the first call_enum_error
(lldb) thread step-over
Process 45200 stopped
* thread #5, stop reason = step over
frame #0: 0x00007ff7c04b31a6 runtime-f95e984830c7562b.exe`static union enum2$<core::result::Result<tuple$<>,anyhow::Error> > runtime::results::run_test(results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, store=0x000000df38cff090) at results.rs:101
98 );
99
100 assert_eq!(
-> 101 results.interface0.call_enum_error(&mut *store, 0.0)?,
102 Err(E::A)
103 );
104 assert_eq!(
(lldb) thread step-over
Process 45200 stopped
* thread #5, stop reason = step over
frame #0: 0x00007ff7c04b4101 runtime-f95e984830c7562b.exe`static union enum2$<core::result::Result<tuple$<>,anyhow::Error> > runtime::results::run_test(results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x000000df38cff2a0, results=0x00007ff7c4bc7d48, store=0x000000df38cff090) at results.rs:166
163 );
164
165 Ok(())
-> 166 }
Yeah, I think that's just telling us what we already know: Wasmtime is trapping with a return pointer not aligned error, which gets returned to the call_enum_error caller as a Result::Err(...), which leads to an early return due to the ? operator.
Basically you're only able to debug the host code, which isn't terribly useful here. It's the guest code we're interested in.
And until we get the debug info issue sorted, we're stuck with e.g. Console.WriteLine-based debugging, AFAICT.
Which has the annoying habit of moving heap related bugs around
Scott, how are you debugging this component?
Slightly interesting that the string Err test is ok
Two months ago, components did not catch any breakpoints
WIth lldb
breakpoint set --file results.rs --line 91
Right, I'll need the compile steps and the invocation
And settings set target.run-args results::run
Can llvm-dwarfdump pick up the dwarf in the component?
And getting the exe name from
C:\github\wit-bindgen>cargo test --package wit-bindgen-cli --test runtime --features csharp-naot --no-default-features -- results::run --exact
Compiling test-artifacts v0.0.0 (C:\github\wit-bindgen\crates\test-rust-wasm\artifacts)
Compiling wit-bindgen-cli v0.26.0 (C:\github\wit-bindgen)
Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 16s
Running tests\runtime\main.rs (target\debug\deps\runtime-f95e984830c7562b.exe)
lldb invocation
lldb target\debug\deps\runtime-f95e984830c7562b.exe
Trying to see where the symbols are inserted into the component
Regarding the bug itself: the pattern I've seen so far is that ulong[] array bodies are only sometimes 8-byte aligned, which might mean they're really 4-byte aligned and 8-byte alignment is only coincidental. Not sure if that's a C# ABI thing or what.
We can ask for sure
Had a lovely lunch with the crew yesterday about this in fact
I love chatting about alignment at lunch.
Oh shit now I'm going to have to compile this and test the debugging
What llvm version are you using?
I know what's happening during my weekend!
I'm using LLVM 18, but I can't reproduce this locally, so that might be a data point. Not sure what Scott's using ATM.
17.0.1 Win x64
AFAIK, this has only ever happened on Windows (i.e. components built on Windows), which seems bizarre. Wit-bindgen CI has been updated to use WASI-SDK 22 (and thus LLVM 18), and it's happening there, but we only test on Windows currently in CI.
For debugging that is, for the build whatever is in Joel's branch which I assume is wasi-sdk 22
technically there's nothing in wit-bindgen that forces you to use a specific wasi-sdk -- it really just controls what CI uses
oh wait, we use WASI_SDK_PATH I think so 21 is what I seem to have, curious
scott@surface5:~$ llvm-dwarfdump /mnt/c/github/wit-bindgen/target/runtime-tests/results/csharp-results/csharp-wasm.component.wasm
error: /mnt/c/github/wit-bindgen/target/runtime-tests/results/csharp-results/csharp-wasm.component.wasm: invalid version number: 65549
scott@surface5:~$ llvm-dwarfdump --version
LLVM (http://llvm.org/):
LLVM version 17.0.4
Optimized build.
scott@surface5:~$
Not terribly interesting
Yup
I used linux for that as I don't have a windows version of llvm-dwarfdump installed
That's standard. Dwarf dump doesn't know the file type
Ah, yes
OK, so as a complete Linux guy, this windows thing could well be quite different
Which means I'm likely going to have to set up a compete window build
Boooooooooo
@Scott Waye would you mind posting your copy of target/runtime-tests/results/csharp-results/csharp-wasm.component.wasm here? I'd like to run it on Linux to see what happens. Also, I'll post my Linux-built copy.
Unless we can repro with a host program that uses the rust code, and link with wasm-tools or the new thing if that is ready now
csharp-wasm.component.wasm
Sure thing
I'm going to hack my tests/runtime/main.rs to run the component without trying to rebuild it.
ok, so I am able to reproduce it with Scott's build. So the runtime behavior is consistent, at least.
ok, that's good
sorry its late here. I'm out tomorrow but will have a look again on Sunday. Have a good evening
You too!
When you have a chance, please try copying my build to target/runtime-tests/results/csharp-results/csharp-wasm.component.wasm, applying the hacky patch below, and running cargo test --no-default-features --features csharp-naot results::run to verify that my build works.
diff --git a/tests/runtime/main.rs b/tests/runtime/main.rs
index fd89888..504b03c 100644
--- a/tests/runtime/main.rs
+++ b/tests/runtime/main.rs
@@ -145,7 +145,7 @@ fn tests(name: &str, dir_name: &str) -> Result<Vec<PathBuf>> {
let wasi_adapter =
std::fs::read(&test_artifacts::ADAPTER).context("failed to read the wasi adapter")?;
- drop(std::fs::remove_dir_all(&out_dir));
+ //drop(std::fs::remove_dir_all(&out_dir));
std::fs::create_dir_all(&out_dir)?;
if cfg!(feature = "rust") && !rust.is_empty() {
@@ -664,7 +664,7 @@ fn tests(name: &str, dir_name: &str) -> Result<Vec<PathBuf>> {
for path in c_sharp.iter() {
let world_name = &resolve.worlds[world].name;
let out_dir = out_dir.join(format!("csharp-{}", world_name));
- drop(fs::remove_dir_all(&out_dir));
+ //drop(fs::remove_dir_all(&out_dir));
fs::create_dir_all(&out_dir).unwrap();
for csharp_impl in &c_sharp {
@@ -765,7 +765,7 @@ fn tests(name: &str, dir_name: &str) -> Result<Vec<PathBuf>> {
out_wasm
));
let component_path = out_wasm.with_extension("component.wasm");
- fs::write(&component_path, component).expect("write component to disk");
+ //fs::write(&component_path, component).expect("write component to disk");
result.push(component_path);
}
Ralph said:
That's standard. Dwarf dump doesn't know the file type
However https://wa2.dev does identify that the sections are present
image.png
Joel Dice said:
ok, so I am able to reproduce it with Scott's build. So the runtime behavior is consistent, at least.
And I confirm that your wasm runs successfully on windows.
https://github.com/dotnet/runtimelab/issues/2606 I created this question because I started to try aligning the return area correctly, but I may be missing something simple. As an alternative we could drop the thread static for now, just leak the buffers, just to pass the tests, obviously we need a correct solution, there is another cleanup that is missing also while we are talking about missing bits.
@Scott Waye I saw https://github.com/dotnet/runtimelab/pull/2609 has been merged (thanks so much for doing that!), so I tried re-running the failed jobs for https://github.com/bytecodealliance/wit-bindgen/pull/968, expecting it to pick up the new NuGet package, but I'm still getting a "return pointer not aligned". Is there something I need to do to make sure the latest release is used?
Yup, good test
The packages are published, I will try a bit later. A little confused as https://github.com/bytecodealliance/wit-bindgen/pull/968/commits/5d0455a1ecd97fe2488374a8fc09001c3936a43a was green a few days ago. Did you comment out the test?
Oh yeah, I updated the test I added in that PR to only use 32-bit values as a workaround, since I'd didn't want it blocked on an unrelated issue.
got it, thanks
Last updated: Dec 13 2025 at 20:04 UTC