Version: v0.16.0 (1cca996e96f29ab2be7ae9f8cfe532bbc92e1dd6)
Platform: macOS 15.7.7, Intel, Xcode 26.6 / AppleClang 21
Host: Ableton Live 11.3.43
Plugin: a CLAP instrument (aumu) built clap-first via make_clapfirst_plugins(), 48 parameters
Summary
createParameterTree() in src/detail/auv3/auv3_parameters.mm sets
kAudioUnitParameterFlag_CFNameRelease on every AUParameter it creates. That flag is an
ownership transfer: it tells the host that the CFStringRef in the v2-style
AudioUnitParameterInfo is +1 and must be released after use.
Apple's AUv3 → v2 bridge populates that struct from the AUParameter's displayName
property without adding a matching retain. So any host that honours the flag releases a
string it never owned. The AUParameter itself survives — which is why the crash appears in
a property read rather than on the object — but its name ivar becomes a dangling pointer.
Ableton Live segfaults while scanning the plugin.
The over-release is cumulative and per-parameter, so exposure scales with parameter count.
Our plugin had recently gone from 16 parameters to 48, which is when this became reproducible
on every scan.
Crash
Exception: EXC_BAD_ACCESS (SIGSEGV)
Subtype: KERN_INVALID_ADDRESS at 0x00001d9e72343fc0
Faulting thread 0 (MainThread):
libobjc.A.dylib objc_retain
libobjc.A.dylib objc_getProperty
AudioToolboxCore AUv3InstanceBase::ParameterMap::parameterInfo(unsigned int, unsigned int, AudioUnitParameterInfo&)
AudioToolboxCore AUv3InstanceBase::GetProperty(...)
AudioToolboxCore AudioUnitGetProperty
Live ...
The plugin's own binary appears nowhere in the stack.
Offending code
src/detail/auv3/auv3_parameters.mm, in createParameterTree():
AudioUnitParameterOptions flags =
kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsHighResolution |
kAudioUnitParameterFlag_HasCFNameString | kAudioUnitParameterFlag_CFNameRelease;
Fix
Dropping the two CFName flags resolves it. Confirmed: with this change Live loads and plays
the plugin normally.
AudioUnitParameterOptions flags =
kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsHighResolution;
kAudioUnitParameterFlag_HasCFNameString goes with it because it only has meaning alongside
the release contract — without it the bridge supplies names from the AUParameter itself,
which is where a v3 host reads them anyway. Parameter names still display correctly in Live
after the change.
If you'd prefer to keep HasCFNameString, dropping CFNameRelease alone should be
sufficient to fix the crash; we did not test that combination separately.
Why this has not been caught before
auval passes straight through it. We had a full AU VALIDATION SUCCEEDED — render at
six sample rates, MIDI, parameter setting, Loaded AudioUnit out-of-process: true — on the
same build that was hard-crashing Live. The validator drives the v2 render API and never
enumerates parameter info the way a host does, so it never triggers the over-release.
That combination — validator green, host dead — is probably why this survived in a release.
It may also be worth noting for anyone else relying on auval as their AUv3 gate.
Reproducing
- Build any clap-first AUv3 with a reasonable number of parameters (ours has 48; fewer may
need more scans before the refcount reaches zero).
- Launch the containing app once so the appex registers.
- Enable Audio Units v3 in Live and rescan.
Disclosure, as with #512: this investigation was carried out by an AI assistant (Claude,
via Claude Code) working with me on my synth project, and I've reviewed it before posting.
The crash log, the source reading and the fix verification are all real and were run on my
machine — but you should know a language model wrote the analysis above, in case that
changes how you'd like to check it.
Version: v0.16.0 (
1cca996e96f29ab2be7ae9f8cfe532bbc92e1dd6)Platform: macOS 15.7.7, Intel, Xcode 26.6 / AppleClang 21
Host: Ableton Live 11.3.43
Plugin: a CLAP instrument (
aumu) built clap-first viamake_clapfirst_plugins(), 48 parametersSummary
createParameterTree()insrc/detail/auv3/auv3_parameters.mmsetskAudioUnitParameterFlag_CFNameReleaseon everyAUParameterit creates. That flag is anownership transfer: it tells the host that the
CFStringRefin the v2-styleAudioUnitParameterInfois +1 and must be released after use.Apple's AUv3 → v2 bridge populates that struct from the
AUParameter'sdisplayNameproperty without adding a matching retain. So any host that honours the flag releases a
string it never owned. The
AUParameteritself survives — which is why the crash appears ina property read rather than on the object — but its name ivar becomes a dangling pointer.
Ableton Live segfaults while scanning the plugin.
The over-release is cumulative and per-parameter, so exposure scales with parameter count.
Our plugin had recently gone from 16 parameters to 48, which is when this became reproducible
on every scan.
Crash
The plugin's own binary appears nowhere in the stack.
Offending code
src/detail/auv3/auv3_parameters.mm, increateParameterTree():AudioUnitParameterOptions flags = kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsHighResolution | kAudioUnitParameterFlag_HasCFNameString | kAudioUnitParameterFlag_CFNameRelease;Fix
Dropping the two CFName flags resolves it. Confirmed: with this change Live loads and plays
the plugin normally.
AudioUnitParameterOptions flags = kAudioUnitParameterFlag_IsReadable | kAudioUnitParameterFlag_IsHighResolution;kAudioUnitParameterFlag_HasCFNameStringgoes with it because it only has meaning alongsidethe release contract — without it the bridge supplies names from the
AUParameteritself,which is where a v3 host reads them anyway. Parameter names still display correctly in Live
after the change.
If you'd prefer to keep
HasCFNameString, droppingCFNameReleasealone should besufficient to fix the crash; we did not test that combination separately.
Why this has not been caught before
auvalpasses straight through it. We had a fullAU VALIDATION SUCCEEDED— render atsix sample rates, MIDI, parameter setting,
Loaded AudioUnit out-of-process: true— on thesame build that was hard-crashing Live. The validator drives the v2 render API and never
enumerates parameter info the way a host does, so it never triggers the over-release.
That combination — validator green, host dead — is probably why this survived in a release.
It may also be worth noting for anyone else relying on
auvalas their AUv3 gate.Reproducing
need more scans before the refcount reaches zero).
Disclosure, as with #512: this investigation was carried out by an AI assistant (Claude,
via Claude Code) working with me on my synth project, and I've reviewed it before posting.
The crash log, the source reading and the fix verification are all real and were run on my
machine — but you should know a language model wrote the analysis above, in case that
changes how you'd like to check it.