You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've been running address sanitizer builds of open source plugins and this plugin had a few crashes in different layers of the code.
The crashes are around how lookup table accesses are implemented, say the range is [0.0, 1.0] and we're try to look up a value for exactly 1.0, the code is accessing one off the end of the array.
I don't know if these out of bounds accesses actually cause crashes, I haven't reproduced a crash in a non ASAN build, but these crashes do look like they could be the cause of bugs #64 and #80.
Configuration
OS: macOS 12.5 Beta
HW: M1 Max MacBook Pro
Rack: 5551617afff182925940908eaf73a7d7361303cc
Plugin: a1cd335
Arch: Both apple silicon native builds and x86 fail
Steps
Build Rack and the AudibleInstruments plugin with ASAN enabled (should be possible on Linux or Mac)
make -j10 EXTRA_FLAGS=-fsanitize=address EXTRA_LDFLAGS=-fsanitize=address
You may also need the following plugins to reproduce with the vcv patch I used
Right click on the AUDIO module and set an output source (should reproduce first 2 issues)
Delete the AUDIO module (reproduces the third issue)
Results
ASAN reports out of bounds accesses. I've detailed the 3 issues I ran into below. After applying workarounds I was unable to cause any more ASAN crashes with this patch, although clearly there are other issues in the source as these are just point fixes in some of the interpolation functions and there are others written in a similar way.
The workarounds I applied are likely not the real fixes, but they got me to the next issue.
1. Plaits - activeEngines
ASAN Crash Log
==89595==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x000204265acf at pc 0x00001aa717ac bp 0x000204265a70 sp 0x000204265a68
WRITE of size 1 at 0x000204265acf thread T16
#0 0x1aa717ab in Plaits::process(rack::engine::Module::ProcessArgs const&) Plaits.cpp:168
#1 0x15f5868 in rack::engine::Module::doProcess(rack::engine::Module::ProcessArgs const&) Module.cpp
#2 0x15df4b7 in rack::engine::Engine::stepBlock(int) Engine.cpp:551
#3 0x12dbe5e in rack::audio::Device::processBuffer(float const*, int, float*, int, int) audio.cpp:45
#4 0x137969f in rack::RtAudioDevice::rtAudioCallback(void*, void*, unsigned int, double, unsigned int, void*) rtaudio.cpp:213
#5 0x1ae2cd4 in RtApiCore::callbackEvent(unsigned int, AudioBufferList const*, AudioBufferList const*) RtAudio.cpp:1768
#6 0x1ae1d54 in callbackHandler(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*) RtAudio.cpp:926
#7 0x7ff804f5462c in HALC_ProxyIOContext::IOWorkLoop()+0x1cde (CoreAudio:x86_64+0x1bb62c)
#8 0x7ff804f52384 in invocation function for block in HALC_ProxyIOContext::HALC_ProxyIOContext(unsigned int, unsigned int)+0x3e (CoreAudio:x86_64+0x1b9384)
#9 0x7ff80511e795 in HALB_IOThread::Entry(void*)+0x47 (CoreAudio:x86_64+0x385795)
#10 0x7ff80354d4e0 in _pthread_start+0x7c (libsystem_pthread.dylib:x86_64+0x64e0)
#11 0x7ff803548f6a in thread_start+0xe (libsystem_pthread.dylib:x86_64+0x1f6a)
Address 0x000204265acf is located in stack of thread T16 at offset 79 in frame
#0 0x1aa70aaf in Plaits::process(rack::engine::Module::ProcessArgs const&) Plaits.cpp:132
This frame has 11 object(s):
[32, 36) 'ref.tmp' (line 133)
[48, 52) 'ref.tmp3' (line 133)
[64, 68) 'blockSize' (line 136)
[80, 96) 'activeEngines' (line 164) <== Memory access at offset 79 underflows this variable
[112, 1648) 'outputFrames' (line 200)
[1776, 1816) 'modulations' (line 203)
[1856, 1904) 'output' (line 221)
[1936, 1940) 'ref.tmp234' (line 233)
[1952, 1956) 'inLen' (line 239)
[1968, 1972) 'outLen' (line 240)
[1984, 2112) 'outputFrame' (line 249)
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
Thread T16 created by T0 here:
#0 0x4928cc in wrap_pthread_create+0x5c (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x418cc)
#1 0x7ff80511eebd in HALB_IOThread::StartAndWaitForState(unsigned int)+0x5ed (CoreAudio:x86_64+0x385ebd)
#2 0x7ff804f56a9e in HALC_ProxyIOContext::_StartIO()+0x14a (CoreAudio:x86_64+0x1bda9e)
#3 0x7ff804f1f178 in HAL_HardwarePlugIn_DeviceStart(AudioHardwarePlugInInterface**, unsigned int, int (*)(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*))+0x2ec (CoreAudio:x86_64+0x186178)
#4 0x7ff805353e6d in HALDevice::StartIOProc(int (*)(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*))+0x55 (CoreAudio:x86_64+0x5bae6d)
#5 0x7ff804da1855 in AudioDeviceStart+0x1f8 (CoreAudio:x86_64+0x8855)
#6 0x1ae22e6 in RtApiCore::startStream() RtAudio.cpp:1602
#7 0x1377f6f in rack::RtAudioDevice::openStream() rtaudio.cpp:129
#8 0x1376ea0 in rack::RtAudioDevice::RtAudioDevice(RtAudio::Api, int) rtaudio.cpp:65
#9 0x1374ced in rack::RtAudioDriver::subscribe(int, rack::audio::Port*) rtaudio.cpp:333
#10 0x12dca6d in rack::audio::Port::setDeviceId(int) audio.cpp:178
#11 0x1448e61 in rack::app::AudioDeviceValueItem::onAction(rack::widget::Widget::ActionEvent const&) AudioDisplay.cpp:88
#12 0x161200d in rack::ui::MenuItem::onDragDrop(rack::widget::Widget::DragDropEvent const&) MenuItem.cpp:62
#13 0x163f2e0 in rack::widget::EventState::handleButton(rack::math::Vec, int, int, int) event.cpp:150
#14 0x7ff8060f2f07 in -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:]+0xa8f (AppKit:x86_64+0x1b0f07)
#15 0x7ff8060f225d in -[NSWindow(NSEventRouting) sendEvent:]+0x15f (AppKit:x86_64+0x1b025d)
#16 0x7ff8060f0633 in -[NSApplication(NSEvent) sendEvent:]+0x15f (AppKit:x86_64+0x1ae633)
#17 0x1720c30 in _glfwPollEventsCocoa cocoa_window.m:1419
#18 0x164b024 in rack::window::Window::step() Window.cpp:431
#19 0x164adc3 in rack::window::Window::run() Window.cpp:409
#20 0x149e1 in main standalone.cpp:240
#21 0x10002952d in start+0x1cd (dyld:x86_64+0x552d)
SUMMARY: AddressSanitizer: stack-buffer-overflow Plaits.cpp:168 in Plaits::process(rack::engine::Module::ProcessArgs const&)
Shadow bytes around the buggy address:
0x10004084cb00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004084cb10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004084cb20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004084cb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10004084cb40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10004084cb50: f1 f1 f1 f1 f8 f2 f8 f2 04[f2]00 00 f2 f2 f8 f8
0x10004084cb60: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x10004084cb70: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x10004084cb80: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x10004084cb90: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x10004084cba0: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==89595==ABORTING
Debugger
(lldb)
frame #5: 0x000000001aa717ac plugin.dylib`Plaits::process(this=0x0000000024c5c800, args=0x0000000204266840) at Plaits.cpp:168:33
165 bool pulse = false;
166 for (int c = 0; c < channels; c++) {
167 int activeEngine = voice[c].active_engine();
-> 168 activeEngines[activeEngine] = true;
169 // Pulse the light if at least one voice is using a different engine.
170 if (activeEngine != patch.engine)
171 pulse = true;
(lldb) p activeEngine
(int) $1 = -1 # Negative array index - Out of bounds
Workaround
diff --git a/src/Plaits.cpp b/src/Plaits.cpp
index a20142d..2dd075e 100644
--- a/src/Plaits.cpp
+++ b/src/Plaits.cpp
@@ -165,10 +165,13 @@ struct Plaits : Module {
bool pulse = false;
for (int c = 0; c < channels; c++) {
int activeEngine = voice[c].active_engine();
- activeEngines[activeEngine] = true;
- // Pulse the light if at least one voice is using a different engine.
- if (activeEngine != patch.engine)
- pulse = true;
+ if(activeEngine >= 0 && activeEngine < 16)
+ {
+ activeEngines[activeEngine] = true;
+ // Pulse the light if at least one voice is using a different engine.
+ if (activeEngine != patch.engine)
+ pulse = true;
+ }
}
// Set model lights
2. stmlib - Interpolate
ASAN Crash Log
==90501==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00001ae76e24 at pc 0x00001abee3a6 bp 0x000204265760 sp 0x000204265758
READ of size 4 at 0x00001ae76e24 thread T13
#0 0x1abee3a5 in stmlib::Interpolate(float const*, float, float) dsp.h:47
#1 0x1ace32bf in clouds::GranularProcessor::Process(clouds::ShortFrame*, clouds::ShortFrame*, unsigned long) granular_processor.cc:278
#2 0x1a97a514 in Clouds::process(rack::engine::Module::ProcessArgs const&) Clouds.cpp:197
#3 0x15f5868 in rack::engine::Module::doProcess(rack::engine::Module::ProcessArgs const&) Module.cpp
#4 0x15df4b7 in rack::engine::Engine::stepBlock(int) Engine.cpp:551
#5 0x12dbe5e in rack::audio::Device::processBuffer(float const*, int, float*, int, int) audio.cpp:45
#6 0x137969f in rack::RtAudioDevice::rtAudioCallback(void*, void*, unsigned int, double, unsigned int, void*) rtaudio.cpp:213
#7 0x1ae2cd4 in RtApiCore::callbackEvent(unsigned int, AudioBufferList const*, AudioBufferList const*) RtAudio.cpp:1768
#8 0x1ae1d54 in callbackHandler(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*) RtAudio.cpp:926
#9 0x7ff804f5462c in HALC_ProxyIOContext::IOWorkLoop()+0x1cde (CoreAudio:x86_64+0x1bb62c)
#10 0x7ff804f52384 in invocation function for block in HALC_ProxyIOContext::HALC_ProxyIOContext(unsigned int, unsigned int)+0x3e (CoreAudio:x86_64+0x1b9384)
#11 0x7ff80511e795 in HALB_IOThread::Entry(void*)+0x47 (CoreAudio:x86_64+0x385795)
#12 0x7ff80354d4e0 in _pthread_start+0x7c (libsystem_pthread.dylib:x86_64+0x64e0)
#13 0x7ff803548f6a in thread_start+0xe (libsystem_pthread.dylib:x86_64+0x1f6a)
0x00001ae76e24 is located 60 bytes to the left of global variable 'clouds::lut_xfade_out' defined in 'eurorack/clouds/resources.cc:1543:13' (0x1ae76e60) of size 68
0x00001ae76e24 is located 0 bytes to the right of global variable 'clouds::lut_xfade_in' defined in 'eurorack/clouds/resources.cc:1536:13' (0x1ae76de0) of size 68
SUMMARY: AddressSanitizer: global-buffer-overflow dsp.h:47 in stmlib::Interpolate(float const*, float, float)
Shadow bytes around the buggy address:
0x1000035ced70: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x1000035ced80: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x1000035ced90: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x1000035ceda0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x1000035cedb0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
=>0x1000035cedc0: 00 00 00 00[04]f9 f9 f9 f9 f9 f9 f9 00 00 00 00
0x1000035cedd0: 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
0x1000035cede0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000035cedf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000035cee00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000035cee10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Thread T13 created by T0 here:
#0 0x4928cc in wrap_pthread_create+0x5c (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x418cc)
#1 0x7ff80511eebd in HALB_IOThread::StartAndWaitForState(unsigned int)+0x5ed (CoreAudio:x86_64+0x385ebd)
#2 0x7ff804f56a9e in HALC_ProxyIOContext::_StartIO()+0x14a (CoreAudio:x86_64+0x1bda9e)
#3 0x7ff804f1f178 in HAL_HardwarePlugIn_DeviceStart(AudioHardwarePlugInInterface**, unsigned int, int (*)(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*))+0x2ec (CoreAudio:x86_64+0x186178)
#4 0x7ff805353e6d in HALDevice::StartIOProc(int (*)(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*))+0x55 (CoreAudio:x86_64+0x5bae6d)
#5 0x7ff804da1855 in AudioDeviceStart+0x1f8 (CoreAudio:x86_64+0x8855)
#6 0x1ae22e6 in RtApiCore::startStream() RtAudio.cpp:1602
#7 0x1377f6f in rack::RtAudioDevice::openStream() rtaudio.cpp:129
#8 0x1376ea0 in rack::RtAudioDevice::RtAudioDevice(RtAudio::Api, int) rtaudio.cpp:65
#9 0x1374ced in rack::RtAudioDriver::subscribe(int, rack::audio::Port*) rtaudio.cpp:333
#10 0x12dca6d in rack::audio::Port::setDeviceId(int) audio.cpp:178
#11 0x1448e61 in rack::app::AudioDeviceValueItem::onAction(rack::widget::Widget::ActionEvent const&) AudioDisplay.cpp:88
#12 0x161200d in rack::ui::MenuItem::onDragDrop(rack::widget::Widget::DragDropEvent const&) MenuItem.cpp:62
#13 0x163f2e0 in rack::widget::EventState::handleButton(rack::math::Vec, int, int, int) event.cpp:150
#14 0x7ff8060f2f07 in -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:]+0xa8f (AppKit:x86_64+0x1b0f07)
#15 0x7ff8060f225d in -[NSWindow(NSEventRouting) sendEvent:]+0x15f (AppKit:x86_64+0x1b025d)
#16 0x7ff8060f0633 in -[NSApplication(NSEvent) sendEvent:]+0x15f (AppKit:x86_64+0x1ae633)
#17 0x1720c30 in _glfwPollEventsCocoa cocoa_window.m:1419
#18 0x164b024 in rack::window::Window::step() Window.cpp:431
#19 0x164adc3 in rack::window::Window::run() Window.cpp:409
#20 0x149e1 in main standalone.cpp:240
#21 0x10002952d in start+0x1cd (dyld:x86_64+0x552d)
==90501==ABORTING
Debugger
(lldb)
frame #5: 0x000000001abee3a6 plugin.dylib`stmlib::Interpolate(table=0x000000001ae76de0, index=16, size=16) at dsp.h:47:13
44 index *= size;
45 MAKE_INTEGRAL_FRACTIONAL(index)
46 float a = table[index_integral];
-> 47 float b = table[index_integral + 1];
48 return a + (b - a) * index_fractional;
49 }
50
(lldb) p index_integral
(int32_t) $1 = 16 # table is 17 elements long so index 16 + 1 is out of bounds
(lldb) up
frame #6: 0x000000001ace32c0 plugin.dylib`clouds::GranularProcessor::Process(this=0x00006250001d6100, input=0x0000000204265ce0, output=0x0000000204265ee0, size=32) at granular_processor.cc:278:21
275 ParameterInterpolator dry_wet_mod(&dry_wet_, parameters_.dry_wet, size);
276 for (size_t i = 0; i < size; ++i) {
277 float dry_wet = dry_wet_mod.Next();
-> 278 float fade_in = Interpolate(lut_xfade_in, dry_wet, 16.0f);
279 float fade_out = Interpolate(lut_xfade_out, dry_wet, 16.0f);
280 float l = static_cast<float>(input[i].l) / 32768.0f * fade_out;
281 float r = static_cast<float>(input[i].r) / 32768.0f * fade_out;
(lldb) p dry_wet
(float) $2 = 1 # Maximum value of 1.0 - is Interpolate supposed to accept [0.0, 1.0] inclusive?
Workaround
This just hacks the one interpolate function that failed, there's other functions that I imagine suffer from the same issue.
The crash on start usually is a one-shot here on my M1 Mini. If I open Rack after crash and tell it to go open patch anyway it will open. Has been reproduced by the folks at VCV and under investigation. However the other issues I have not seen here…
I've been running address sanitizer builds of open source plugins and this plugin had a few crashes in different layers of the code.
The crashes are around how lookup table accesses are implemented, say the range is [0.0, 1.0] and we're try to look up a value for exactly 1.0, the code is accessing one off the end of the array.
I don't know if these out of bounds accesses actually cause crashes, I haven't reproduced a crash in a non ASAN build, but these crashes do look like they could be the cause of bugs #64 and #80.
Configuration
OS: macOS 12.5 Beta
HW: M1 Max MacBook Pro
Rack: 5551617afff182925940908eaf73a7d7361303cc
Plugin: a1cd335
Arch: Both apple silicon native builds and x86 fail
Steps
make -j10 EXTRA_FLAGS=-fsanitize=address EXTRA_LDFLAGS=-fsanitize=address
Results
ASAN reports out of bounds accesses. I've detailed the 3 issues I ran into below. After applying workarounds I was unable to cause any more ASAN crashes with this patch, although clearly there are other issues in the source as these are just point fixes in some of the interpolation functions and there are others written in a similar way.
The workarounds I applied are likely not the real fixes, but they got me to the next issue.
1. Plaits - activeEngines
ASAN Crash Log
Debugger
Workaround
2. stmlib - Interpolate
ASAN Crash Log
Debugger
Workaround
This just hacks the one interpolate function that failed, there's other functions that I imagine suffer from the same issue.
3. Keyframer - easing_curve
ASAN Crash Log
Debugger
Workaround
The text was updated successfully, but these errors were encountered: