Skip to content

[AUv3] Render callback may resize buffers and does not enforce maximumFramesToRender #163

Description

@spkfb

[AUv3] Render callback may resize buffers and does not enforce maximumFramesToRender

Summary

The AUv3 render callback may call scratchBuffer.setSize() while processing audio and does not appear to reject render requests larger than the allocated maximum frame count.

This violates real-time safety requirements and may cause reallocations, unpredictable latency, or buffer misuse on the audio thread.

Severity

P1 — Real-time safety and memory correctness

Affected area

modules/yup_audio_plugin_client/auv3/yup_audio_plugin_client_AUv3.mm

Current behaviour

Scratch-buffer sizing is performed from the render path rather than being fully determined during render-resource allocation.

The callback also does not appear to enforce:

frameCount <= maximumFramesToRender

Impact

  • heap allocation on the real-time audio thread;
  • audio dropouts or priority inversion;
  • inconsistent performance on the first block;
  • possible buffer overruns if preallocated structures are smaller than frameCount;
  • host-dependent failures when render quantum changes.

Steps to reproduce

  1. Build the plugin with allocation instrumentation.
  2. Load it in an AUv3 host.
  3. Start playback.
  4. Change the host buffer size or force the first render at the maximum quantum.
  5. Observe allocations from the render thread.
  6. Invoke the render block with a frame count larger than the configured maximum in a test harness.

Actual result

The render callback may resize storage, and oversized frame counts may not be rejected explicitly.

Expected result

All render storage must be allocated in allocateRenderResourcesAndReturnError().

The render callback must:

  • perform no heap allocations;
  • never resize containers;
  • reject invalid frame counts;
  • use only preallocated storage.

Suggested fix

During resource allocation:

const auto maxFrames = au.maximumFramesToRender;
scratchBuffer.setSize(totalChannels, static_cast<int>(maxFrames), false, true, false);

During rendering:

if (frameCount > allocatedMaximumFrames)
    return kAudioUnitErr_TooManyFramesToProcess;

Preallocate all per-bus AudioBufferList storage at the same time.

Acceptance criteria

  • No heap allocation occurs in the render callback.
  • No container is resized in the render callback.
  • Oversized frame counts return an appropriate error.
  • Buffers are allocated using maximumFramesToRender.
  • Resource deallocation happens outside rendering.
  • Real-time allocation tests pass under repeated rendering.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions