Skip to content

rust: avoid rerunning constructors after WASI startup - #1750

Open
macovedj wants to merge 1 commit into
bytecodealliance:mainfrom
macovedj:ctors-once-after-initialize
Open

macovedj wants to merge 1 commit into
bytecodealliance:mainfrom
macovedj:ctors-once-after-initialize

Conversation

@macovedj

Copy link
Copy Markdown
Contributor

Since rust-lang/rust#161421, _initialize runs constructors in WASI cdylibs before the first export call, but wit-bindgen’s separate RUN guard remains unset, so run_ctors_once runs them again.

This PR registers an .init_array marker that sets the existing RUN guard when constructors run. Exported functions can then recognize initialization already performed by _initialize or _start

Register a startup marker that sets the existing run-once flag when constructors are invoked by _initialize or _start. Preserve the older toolchain fallback and add a constructor-counting component test covering the first and second export calls.
@alexcrichton

Copy link
Copy Markdown
Member

Thanks! I think it might actually be time though to just go ahead and outright delete this workaround. IIRC this was needed for... something in the past but I have no idea what, and I also have a vague recollection that the need for it was fixed long ago. Mind just deleting all the infrastructure to do this instead?

@macovedj

Copy link
Copy Markdown
Contributor Author

Looks to me like this is the original issue. I started looking into removal, and for wasm32-unknown-unknown, LLD still generates per-export constructor wrappers, including around cabi_realloc. I think we could still remove the workaround, but those builds need replacement startup support first. I’m looking into providing _initialize and suppressing those wrappers in wasm-component-ld. Should be able to have something up over there soon.

@alexcrichton

Copy link
Copy Markdown
Member

Another possible fix might be to limit the workaround to non-wasi targets since I think it's just the wasi targets using _initialize nowadays, but a deeper fix would work too!

@macovedj

Copy link
Copy Markdown
Contributor Author

Ah that would be easier to implement. One other wrinkle though. Removing the work around for wasi targets before rust 1.100 breaks since when cdylibs will start getting crt-reactor.o and _initialize.

The cleanest option I see is a build script that no-ops run_ctors_once once the compiler is new enough to guarantee that, defaulting to the current fallback when detection fails. Alternatively, wasm-component-ld could handle this itself, since it sees the whole link, but then the switch is keyed to the linker version rather than the Rust version.

Unless there's another mechanism I'm missing, I'd guess merging this as is for now and revisiting the deletion once our MSRV reaches a Rust version where _initialize is guaranteed for WASI cdylibs is what makes the most sense. I'd be happy to own a tracking issue if we go that route.

If you have any simpler approaches in mind, I'm happy go for one of those too.

@alexcrichton

Copy link
Copy Markdown
Member

Personally I'd prefer to time-box the workaround here to avoid it getting cemented too much -- I think the best option for now would be to detect the rustc version in a build script and then change this function based on that. Once MSRV is beyond that then this can all be dropped entriely

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants