https://bugs.winehq.org/show_bug.cgi?id=54831
Bug ID: 54831 Summary: GStreamer gst_init_check() crashes when called from winegstreamer on recent macOS Product: Wine Version: 8.5 Hardware: x86-64 OS: Mac OS X Status: UNCONFIRMED Severity: normal Priority: P2 Component: loader Assignee: wine-bugs@winehq.org Reporter: bshanks@codeweavers.com
On macOS Ventura (and I suspect Monterey), gst_init_check() crashes (trying to jump to 0x0) when called by winegstreamer. This is caused by the macOS preloader, here's how:
* gst_init_check() calls init_static_plugins() https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/1.22/subprojects/gstreamer/gst/gst.c#L625, which through some GModule abstractions does a dlopen(NULL) and dlsym() for a symbol that doesn't exist. dlsym() returns NULL, but GModule also calls dlerror() which returns NULL (signaling no error). * init_static_plugins() therefore thinks that the dlsym() was successful, doesn't do a NULL pointer check, and jumps to the NULL pointer.
The issue here is dlerror() returning NULL despite there being an error to report. Looking at the macOS dyld source code (https://github.com/apple-oss-distributions/dyld/blob/dyld-1042.1/dyld/DyldAPIs.cpp#L1206), dlerror() always returns NULL if libSystem was not initialized in the process. And sure enough, when running vmmap on a Wine process, the message "Process exists but has not fully started -- dyld has initialized but libSystem has not" is printed.
After more searching in dyld, it turns out that dyld initializes libSystem for binaries targeting 10.5 and newer. The Wine preloader targets 10.7 (since that's the newest target that will generate an LC_UNIXTHREAD binary, critical to how the preloader works). But dyld determines the target OS based on where the program vars (argc, argv, environ, etc) are stored, and a 10.6/10.7 binary should contain a __program_vars section for those. The preloader is missing that, and so (I believe) it falls down to being considered a 10.4 binary. A 10.4 binary should init libSystem in its own _start, but the preloader also doesn't do this, and libSystem stays uninitialized.
(See https://github.com/apple-oss-distributions/dyld/blob/dyld-1042.1/common/MachOAnalyzer.cpp#L2185 for where this is determined)
I see several possible solutions:
* The most obvious one: add a __program_vars section to the preloader, to make it a correct 10.7 binary. In fact, the code can basically be copied out of Apple's C startup code (https://github.com/apple-opensource/Csu/blob/88/crt.c#L47). This does work, and libSystem gets initialized. However, libSystem is initialized before any preloader code runs, and malloc zones are already in the middle of areas we want to reserve. That's bad; by itself this approach won't work, but it might if we also:
- add linker zerofill sections to block off the entire low 4GB. This is desirable to reserve as much address space as possible for 32-bit EXEs in wow64 mode.
- and if zerofill sections are also added to reserve the area where 64-bit EXEs generally load (0x14000000), it might even be possible to stop using the preloader altogether on 64-bit.
* Alternately, go the other way, and lean in to being a 10.4 binary. In that case, _start in the preloader needs to call back into dyld to initialize things (like this: https://github.com/apple-opensource/Csu/blob/88/crt.c#L219). We could do this after reserving our areas. I'm leery of this approach, mainly because x86_64/10.4 was not a popular target (GUI apps were not supported, they could only link against libSystem). If possible, I'd rather not target such an obscure combination. The preloader has been a source of problems with new OS versions, and I'd like to decrease the amount of black magic it's doing, not increase it. (Running 10.4 x86_64 binaries on modern macOS is still supported though, and Xcode can even still build them.)
I'd like to make the __program_vars+zerofill approach work if possible.
https://bugs.winehq.org/show_bug.cgi?id=54831
--- Comment #1 from Brendan Shanks bshanks@codeweavers.com --- Under macOS Sonoma, Wine crashes with an odd "objc[89070]: -[NSObject methodSignatureForSelector:] not available without CoreFoundation" ObjC exception.
The root cause is the same as this issue: libSystem needs to be initialized, using one of the two methods mentioned. I'm still pursuing the __program_vars+zerofill approach, but I'll attach a patch that uses the other method (useful as a short-term fix, or for older Wine versions).
https://bugs.winehq.org/show_bug.cgi?id=54831
--- Comment #2 from Brendan Shanks bshanks@codeweavers.com --- Created attachment 74661 --> https://bugs.winehq.org/attachment.cgi?id=74661 patch to call _dyld_make_delayed_module_initializer_calls() in preloader
https://bugs.winehq.org/show_bug.cgi?id=54831
Brendan Shanks bshanks@codeweavers.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Summary|GStreamer gst_init_check() |GStreamer gst_init_check() |crashes when called from |crashes when called from |winegstreamer on recent |winegstreamer on recent |macOS |macOS, also Wine crashes on | |macOS Sonoma
https://bugs.winehq.org/show_bug.cgi?id=54831
Fabian Maurer dark.shadow4@web.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |dark.shadow4@web.de
--- Comment #3 from Fabian Maurer dark.shadow4@web.de --- Why does the preloader has to depend on libSystem to begin with? I thought the point of the preloader is that it runs before any other library functions, so making it run after libSystem sounds weird. If we use that zerofill approach, would the preloader still be needed?
https://bugs.winehq.org/show_bug.cgi?id=54831
--- Comment #4 from Brendan Shanks bshanks@codeweavers.com --- (In reply to Fabian Maurer from comment #3)
Why does the preloader has to depend on libSystem to begin with? I thought the point of the preloader is that it runs before any other library functions, so making it run after libSystem sounds weird. If we use that zerofill approach, would the preloader still be needed?
Yes that is the idea of the preloader, but macOS doesn’t provide any supported way to do this and our unsupported method has been increasingly problematic on recent macOS versions (particularly since Monterey). dyld is now reserving some low memory before the preloader runs, and libSystem has to be initialized at some point.
You’re right that the preloader running after libSystem is weird, this is really just a step towards hopefully removing it (for x86_64). My hope is that a large-enough zerofill section (over the low 8GB) would reserve anywhere that an EXE needs to load and then the preloader will no longer be needed. (This is possible now that the PE separation is complete, since there are no requirements on where dlopen()’d libraries end up in memory)
https://bugs.winehq.org/show_bug.cgi?id=54831
--- Comment #5 from Fabian Maurer dark.shadow4@web.de --- I only have an M1 Mac, anyways I could help?
https://bugs.winehq.org/show_bug.cgi?id=54831
Gcenx gcenx83@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |gcenx83@gmail.com
--- Comment #6 from Gcenx gcenx83@gmail.com --- (In reply to Brendan Shanks from comment #2)
Created attachment 74661 [details] patch to call _dyld_make_delayed_module_initializer_calls() in preloader
Thats pretty much what I’m currently applying for the Winehq macOS packages since it seems everyone and there mother have upgraded to macOS Sonoma beta….
https://bugs.winehq.org/show_bug.cgi?id=54831
Brendan Shanks bshanks@codeweavers.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |FIXED Fixed by SHA1| |4e6dbf3b9efc4974e4c5b8f2f56 | |03655f7958cbd Status|UNCONFIRMED |RESOLVED
--- Comment #7 from Brendan Shanks bshanks@codeweavers.com --- This should be fixed, the preloader now has the zerofill section and a __program_vars section
https://bugs.winehq.org/show_bug.cgi?id=54831
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #8 from Alexandre Julliard julliard@winehq.org --- Closing bugs fixed in 8.14.