Skip to content

Conversation

gxalpha
Copy link
Member

@gxalpha gxalpha commented Sep 2, 2025

Description

RTLD_LAZY means that symbols will only be resolved when first used, while RTLD_NOW tries to resolve them immediately. This means that if there are missing symbols (e.g, because a function got removed from libobs), dlopen with RTLD_LAZY will happily open that module but we get a runtime crash when the module tries to use that symbol, while with RTLD_NOW we instead get a (nicer) error on dlopen.

Motivation and Context

Crashes like the #12565 are annoying. It'd be nicer if we didn't load broken plugins in the first place.
Fixes #12565

How Has This Been Tested?

Tested on macOS 26. Testing from Linux contributors would be appreciated.

Tested with 0.9.4 of the audio-monitor plugin which still uses obs_frontend_add_dock.
Prior to this PR, we get a crash on startup (not ideal).
With this PR, the plugin fails to load, and we get an error message in the log:

error: os_dlopen(/Users/.../Library/Application Support/obs-studio/plugins/audio-monitor.plugin/Contents/MacOS/audio-monitor->/Users/.../Library/Application Support/obs-studio/plugins/audio-monitor.plugin/Contents/MacOS/audio-monitor): dlopen(/Users/.../Library/Application Support/obs-studio/plugins/audio-monitor.plugin/Contents/MacOS/audio-monitor, 0x0106): Symbol not found: _obs_frontend_add_dock
  Referenced from: <3BF6DC09-1B39-30D5-98B5-33D6A4D46655> /Users/.../Library/Application Support/obs-studio/plugins/audio-monitor.plugin/Contents/MacOS/audio-monitor
  Expected in:     <A6A272D8-83B5-3DA7-A67B-D7C2C92AE81B> /Users/.../obs-studio/build_macos/frontend/Debug/OBS.app/Contents/Frameworks/obs-frontend-api.dylib
warning: Module '/Users/.../Library/Application Support/obs-studio/plugins/audio-monitor.plugin/Contents/MacOS/audio-monitor' not loaded
debug: Failed to load module file '/Users/.../Library/Application Support/obs-studio/plugins/audio-monitor.plugin/Contents/MacOS/audio-monitor', file not found

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code has been run through clang-format.
  • I have read the contributing document.
  • My code is not on the master branch.
  • The code has been tested.
  • All commit messages are properly formatted and commits squashed where appropriate.
  • I have included updates to all appropriate documentation.

@tytan652
Copy link
Collaborator

tytan652 commented Sep 2, 2025

Since has_qt5_dependency was not removed, you need to make module_has_qt5_check use dlopen with RTLD_LAZY rather than os_dlopen.

@tytan652
Copy link
Collaborator

tytan652 commented Sep 2, 2025

Also the plugin being not loaded does not show the plugin load error prompt, load_all_callback may need a change to MODULE_FILE_NOT_FOUND (mismatching macro name now) case to a goto.

Edit: But MODULE_MISSING_EXPORTS is a return too and need to stay like this…

@gxalpha
Copy link
Member Author

gxalpha commented Sep 2, 2025

Also the plugin being not loaded does not show the plugin load error prompt

This is currently expected and matches Windows. A proper notification (on all platforms) would be nice but is out-of-scope for this PR.

@gxalpha
Copy link
Member Author

gxalpha commented Sep 2, 2025

Since has_qt5_dependency was not removed, you need to make module_has_qt5_check use dlopen with RTLD_LAZY rather than os_dlopen.

Potentially dumb question, but is the Qt 5 check even needed with RTLD_NOW? I imagine plugins linking against Qt 5 should be rejected by dlopen now?
The behavioral change would be that the message no longer appears, but I think that'd be fine since there shouldn't be that many plugins anymore using Qt 5, so the impact would be rather small.

@tytan652
Copy link
Collaborator

tytan652 commented Sep 2, 2025

On Linux outside of our Flatpak (e.g. Ubuntu), you can end up with Qt 5 and 6 installed side by side.
And you must avoid loading both of them (this creates a mess and qt5ct was a good example) and this check is there because we did not break ABI through SOVERSION when switching to Qt 6.
If you want to remove the check you need #12566 first to fail finding an old libobs.

@PatTheMav
Copy link
Member

While RTLD_LAZY is the preferred default, RTLD_NOW can indeed serve as an additional safety-net as we're loading unchecked 3rd party code. Initial loading will be slower (though the brute force speed of modern architectures will mask this quite a bit) though any consecutive symbol lookup will be faster.

RTLD_LAZY means that symbols will only be resolved when first used,
while RTLD_NOW tries to resolve them immediately. This means that if
there are missing symbols (e.g, because a function got removed from
libobs), dlopen with RTLD_LAZY will happily open that module but we get
a runtime crash when the module tries to use that symbol, while with
RTLD_NOW we instead get a (nicer) error on dlopen.
@gxalpha
Copy link
Member Author

gxalpha commented Sep 2, 2025

@tytan652 I've changed os_dlopen to dlopen with RTLD_LAZY. Would be nice if you could take a look and/or test this as I have no way to (especially whether the .so addition from os_dlopen is required?).

@tytan652
Copy link
Collaborator

tytan652 commented Sep 2, 2025

Would be nice if you could take a look and/or test this as I have no way to (especially whether the .so addition from os_dlopen is required?).

The suffix check is mainly meant for os_dlopen cross-platform use outside of load_all_callback/obs_open_module, so it should be good.

@RytoEX
Copy link
Member

RytoEX commented Sep 2, 2025

Since has_qt5_dependency was not removed, you need to make module_has_qt5_check use dlopen with RTLD_LAZY rather than os_dlopen.

Potentially dumb question, but is the Qt 5 check even needed with RTLD_NOW? I imagine plugins linking against Qt 5 should be rejected by dlopen now? The behavioral change would be that the message no longer appears, but I think that'd be fine since there shouldn't be that many plugins anymore using Qt 5, so the impact would be rather small.

We had actually planned to remove the Qt 5 check for this release, and may still before RC/stable. It was put into place around OBS Studio 28 three years ago for the transition from Qt 5 to Qt 6. We expect that the number of users still having Qt5-based OBS Studio plugins should be incredibly small. cc @kkartaltepe

@RytoEX RytoEX self-assigned this Sep 2, 2025
@RytoEX RytoEX added the Bug Fix Non-breaking change which fixes an issue label Sep 2, 2025
@RytoEX RytoEX added this to the OBS Studio 32.0 milestone Sep 2, 2025
@gxalpha
Copy link
Member Author

gxalpha commented Sep 2, 2025

Should I just undo the changes made to the Linux Qt 5 check here then?

@RytoEX
Copy link
Member

RytoEX commented Sep 2, 2025

Context, we used to always use only RTLD_LAZY, but switched to RTLD_LAZY | RTLD_FIRST for macOS in #956 (a66ad7e). Will defer to @PatTheMav on the changes here.

@PatTheMav
Copy link
Member

Context, we used to always use only RTLD_LAZY, but switched to RTLD_LAZY | RTLD_FIRST for macOS in #956 (a66ad7e). Will defer to @PatTheMav on the changes here.

As mentioned above, using RTLD_NOW is fine, indeed as the man page mentions:

Note: With chained-fixups (the default mach-o format since macOS 12 and iOS 15) using RTLD_LAZY or RTLD_NOW has no effect, as all symbols are immediately bound.

So for any binary built with the macOS 12 deployment target (which plugins won't all be) the effect will be the same as if RTLD_NOW had been used.

RTLD_FIRST influences the behaviour of dlsym to ensure that a symbol is only resolved within the image loaded initially by dlopen and to ignore any matching symbols that might have come into existence since then, which also seems correct for loading plugins.

Copy link
Member

@PatTheMav PatTheMav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

macOS changes should be fine, Linux changes probably as well but defer to Linux maintainers to approve that.

Copy link
Collaborator

@tytan652 tytan652 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on my machine

@RytoEX
Copy link
Member

RytoEX commented Sep 3, 2025

Should I just undo the changes made to the Linux Qt 5 check here then?

We can just leave it in, and deal with it in the revert/removal.

@RytoEX RytoEX merged commit 6242913 into obsproject:master Sep 3, 2025
15 checks passed
@gxalpha gxalpha deleted the rtld_now branch September 3, 2025 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Fix Non-breaking change which fixes an issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OBS 32 Beta1 crashes in normal mode, but not in safe mode.
4 participants