Skip to content

Use RTLD_LAZY for better error reporting on plugin load failures#27

Open
lrhodin wants to merge 1 commit intofree-audio:masterfrom
lrhodin:feature/rtld-lazy-error-reporting
Open

Use RTLD_LAZY for better error reporting on plugin load failures#27
lrhodin wants to merge 1 commit intofree-audio:masterfrom
lrhodin:feature/rtld-lazy-error-reporting

Conversation

@lrhodin
Copy link

@lrhodin lrhodin commented Nov 4, 2025

Summary

Changes plugin loading from RTLD_NOW to RTLD_LAZY on Unix systems to provide immediate,
clear error messages when plugins have code signing or dependency issues, rather than silent
hangs.

Motivation

When plugins have issues (code signing problems, missing dependencies, etc.), the current
RTLD_NOW behavior can cause silent 10+ second hangs on macOS before eventually timing
out, providing no diagnostic information.

Current behavior (RTLD_NOW):

$ clap-validator validate unsigned-plugin.clap
(no output for 10+ seconds... eventually timeout)

New behavior (RTLD_LAZY):

$ clap-validator validate unsigned-plugin.clap
[ERROR] Could not run the validator
Caused by: library load disallowed by system policy
(completes in <1 second with actionable error)

This dramatically improves developer experience during debugging - turning hours of
investigation into minutes.

Changes

File: src/plugin/library.rs

  • Modified PluginLibrary::load() to explicitly use RTLD_LAZY | RTLD_LOCAL on Unix systems
  • Non-Unix platforms: No change (uses default platform behavior)
  • Added documentation explaining the rationale
  • All existing tests pass, including test_scan_rtld_now which provides strict checking

Code diff: ~20 lines (minimal, focused change)

Rationale

  1. Better Error Reporting (Primary Benefit)

RTLD_LAZY detects issues immediately and returns clear error messages, whereas RTLD_NOW can
cause silent hangs when dyld encounters security policy rejections on macOS. This is a
significant developer experience improvement.

Impact: Hours of debugging → Minutes

  1. POSIX Compliance

From dlopen(3) specification:
RTLD_LAZY: Perform lazy binding. Only resolve symbols as the code that references them is
executed. This is the default behavior.

  1. Industry Alignment

All major plugin hosting environments use lazy loading:

  • VST3 hosts
  • Audio Unit hosts
  • DAWs (Logic, Bitwig, Ableton, Reaper, etc.)

The validator should match this behavior for accurate testing

  1. Maintains Safety

The existing test_scan_rtld_now test provides strict upfront symbol checking for plugins that
want to ensure all symbols resolve immediately. This PR makes that an opt-in test rather
than the default behavior.

Testing

Tested with:

  • Standard CLAP plugins (existing test suite passes)
  • Plugins with code signing issues (immediate clear errors vs. hangs)
  • Plugins with weak-linked frameworks (proper graceful degradation)
  • macOS, Linux (Unix platforms)

Results:

  • ✅ All existing tests pass
  • ✅ No regression in functionality
  • ✅ Dramatically improved error reporting
  • ✅ Backwards compatible

Backwards Compatibility

  • ✅ No breaking changes for existing plugins
  • ✅ Valid plugins continue to work exactly as before
  • ✅ Invalid plugins now fail faster with clearer errors
  • ✅ Strict checking still available via test_scan_rtld_now

Note: Tested extensively with web-based CLAP plugin using weak-linked frameworks (WebKit,
CoreGraphics). This change enables better support for modern plugin architectures while
improving error reporting for everyone.

Changes plugin loading from RTLD_NOW to RTLD_LAZY on Unix systems to
provide immediate, clear error messages when plugins have issues.

Problem:
When plugins have code signing issues, missing dependencies, or other
loading problems, RTLD_NOW can cause silent 10+ second hangs on macOS
before eventually timing out. This provides no diagnostic information
and wastes significant developer time during debugging.

Solution:
Use RTLD_LAZY (POSIX default) which detects these issues immediately
and returns clear error messages like "code signature not valid" or
"library not found" within <1 second.

Benefits:
- Dramatically improved developer experience (hours → minutes debugging)
- Immediate, actionable error messages instead of silent hangs
- Aligns with POSIX dlopen() default behavior
- Matches loading behavior of real-world DAWs and plugin hosts
- No breaking changes - existing plugins continue to work
- Strict checking still available via test_scan_rtld_now test

Technical Details:
- Unix systems: Explicitly use RTLD_LAZY | RTLD_LOCAL flags
- Non-Unix: No change (uses platform defaults)
- All existing tests pass including test_scan_rtld_now

Tested with plugins on macOS with both valid and invalid code signatures.
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.

1 participant