Should Juce 7 work OOTB with ASAN?

Seems like I’m hitting exceptions on multiple juce projects in windows with ASAN enabled, using the latest MSVC 2019 toolkits. (VS16.11.25)

Even when exceptions are ignored, I’m still getting immediate runtime exceptions on startup, even though they are disabled in exception settings. Has anybody gotten Juce+ASAN working in a windows 2019 devenv?

-M

This should work. It’s a while since I’ve used the ASAN bundled with VS2019, but it worked as expected in VS2022 a month or so ago.

On older versions of ASAN bundled with MSVC, it was necessary to manually disable access violation exception breakpoints, as described here: https://devblogs.microsoft.com/cppblog/asan-for-windows-x64-and-debug-build-support/#known-issues

It sounds like your version of MSVC should be new enough to avoid that problem, but maybe it’s worth double-checking that you’re definitely using the new toolchain. If that doesn’t help, I recommend trying out VS2022 to see whether you see the same issues there.

Also, if you’re still having problems, you could try disabling the options listed in the official docs: https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#ide-msbuild

1 Like

Yes - I did all of these things. Repro here is with vs2019 and latest juce, with the default audio plugin product. Video:

Any thoughts? I’m not sure how to check for versions, but VS2019 is fully updated, and IDE info is as follows:

Microsoft Visual Studio Community 2019
Version 16.11.25
VisualStudio.16.Release/16.11.25+33423.256
Microsoft .NET Framework
Version 4.8.09032

Installed Version: Community

Visual C++ 2019   00435-00000-00000-AA427
Microsoft Visual C++ 2019

ASP.NET and Web Tools 2019   16.11.115.10959
ASP.NET and Web Tools 2019

C# Tools   3.11.0-4.22108.8+d9bef045c4362fbcab27ef35daec4e95c8ff47e1
C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

IntelliCode Extension   1.0
IntelliCode Visual Studio Extension Detailed Info

Microsoft JVM Debugger   1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft MI-Based Debugger   1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards   1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio VC Package   1.0
Microsoft Visual Studio VC Package

NuGet Package Manager   5.11.2
NuGet Package Manager in Visual Studio. For more information about NuGet, visit https://docs.nuget.org/

ProjectServicesPackage Extension   1.0
ProjectServicesPackage Visual Studio Extension Detailed Info

Test Adapter for Boost.Test   1.0
Enables Visual Studio's testing tools with unit tests written for Boost.Test.  The use terms and Third Party Notices are available in the extension installation directory.

Test Adapter for Google Test   1.0
Enables Visual Studio's testing tools with unit tests written for Google Test.  The use terms and Third Party Notices are available in the extension installation directory.

TypeScript Tools   16.0.30526.2002
TypeScript Tools for Microsoft Visual Studio

Visual Basic Tools   3.11.0-4.22108.8+d9bef045c4362fbcab27ef35daec4e95c8ff47e1
Visual Basic components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Visual Studio Code Debug Adapter Host Package   1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Visual Studio Tools for CMake   1.0
Visual Studio Tools for CMake

Thoughts? I could update, but I have deps that require vs2019 in some of our projects. The probability of that being nontrivial is probably med/high.

I should add that:

  • Continue just results in replaying the same AV error.
  • I’ve disabled the opts in the official docs.

Projucer is set to Default (v142)

Have you tried any non-JUCE projects? If you create a blank GUI app directly in VS, and then enable Asan, do you see the same thing?

Just tried, works - but then I noticed that the config was x86 by default. Swapping configuration to x64 results in the same broken behavior. Oof.

-M

So, update: I was able to get a configuration running ASAN working in vs, but had to create and use an x86 config of the project. For VST3, I also created an x86 version of the APH with the sanitizer enabled. This allows me to load/run/trap issues.

So, its a start. What I’m trying to do is profile random crashes in FL studio that we’re seeing after moving to J7, ones that do not occur in cubase, reaper, etc. Obviously those are x64 hosts, and I believe that even with ASAN on, the host would have to have it built-in to trap anything useful.

I see a lot of spurious open GL errors - even after upgrading to the latest version of 7 that has the refactor. Have you guys been seeing issues?

I don’t have an answer but I’m just curious why you’d be applying ASAN to your project at this stage of development? Just curious.

You might see some diagnostics, but there shouldn’t be any errors. What kind of output are you seeing?

Quite a few variants - here is a stacktrace of one of them. On its face it looks like drawImage is resulting (somehow) in the destruction of an image. The behavior seems to change based on whether or not we enable GL at runtime (it is an option)

We do make use of the Image() copy ctor pretty often. And we have many shared graphics - assigned via Image::getFromMemory() inside the initializer list. I suppose the forced init ones could be refs, but I just figured that Image() is a shallow copy by default, no? When we swap presets we tear down UI elements, then build them back up - so I wonder if Juce is destroying the pixel data when that happens. I feel like we would’ve noticed this before, though.

 	ntdll.dll!00007ff86bddbda2()	Unknown
 	ntdll.dll!00007ff86bde4e7a()	Unknown
 	ntdll.dll!00007ff86bde515a()	Unknown
 	ntdll.dll!00007ff86bdf1155()	Unknown
 	ntdll.dll!00007ff86bd7bd18()	Unknown
 	ntdll.dll!00007ff86bd0ab01()	Unknown
 	igxelpicd64.dll!00007fff945c10e0()	Unknown
 	igxelpicd64.dll!00007fff93e4acd7()	Unknown
 	igxelpicd64.dll!00007fff94065a44()	Unknown
 	igxelpicd64.dll!00007fff93e4aa38()	Unknown
 	igxelpicd64.dll!00007fff94013eeb()	Unknown
 	igxelpicd64.dll!00007fff94061f25()	Unknown
 	igxelpicd64.dll!00007fff94137718()	Unknown
 	igxelpicd64.dll!00007fff93e4a560()	Unknown
 	igxelpicd64.dll!00007fff93e4a452()	Unknown
 	igxelpicd64.dll!00007fff940729e6()	Unknown
>	[Inline Frame] MyApp.vst3!juce::OpenGLTexture::release() Line 173	C++
 	[Inline Frame] MyApp.vst3!juce::OpenGLTexture::{dtor}() Line 36	C++
 	MyApp.vst3!juce::OpenGLRendering::CachedImageList::CachedImage::~CachedImage() Line 107	C++
 	MyApp.vst3!juce::OwnedArray<juce::OpenGLRendering::CachedImageList::CachedImage,juce::DummyCriticalSection>::remove(int indexToRemove, bool) Line 581	C++
 	MyApp.vst3!juce::OpenGLRendering::CachedImageList::imageDataBeingDeleted(juce::ImagePixelData * im) Line 173	C++
 	[Inline Frame] MyApp.vst3!juce::ImagePixelData::{dtor}::__l2::<lambda_5a0e1f191daa5ba6f147b6bd62e8754e>::operator()(juce::ImagePixelData::Listener &) Line 38	C++
 	[Inline Frame] MyApp.vst3!juce::ListenerList<juce::ImagePixelData::Listener,juce::Array<juce::ImagePixelData::Listener *,juce::DummyCriticalSection,0>>::call(juce::ImagePixelData::{dtor}::__l2::<lambda_5a0e1f191daa5ba6f147b6bd62e8754e> &&) Line 140	C++
 	MyApp.vst3!juce::ImagePixelData::~ImagePixelData() Line 38	C++
 	[External Code]	
 	[Inline Frame] MyApp.vst3!juce::ContainerDeletePolicy<juce::ImagePixelData>::destroy(juce::ImagePixelData *) Line 54	C++
 	[Inline Frame] MyApp.vst3!juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::decIfNotNull(juce::ImagePixelData * o) Line 449	C++
 	[Inline Frame] MyApp.vst3!juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::{dtor}() Line 374	C++
 	[Inline Frame] MyApp.vst3!juce::Image::{dtor}() Line 268	C++
 	MyApp.vst3!juce::Graphics::drawImage(const juce::Image & imageToDraw, int dx, int dy, int dw, int dh, int sy, int sw, int sh, int) Line 834	C++
 	MyApp.vst3!FilmstripToggle::paint(juce::Graphics & g) Line 47	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2010	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::OpenGLContext::CachedImage::paintOwner(juce::LowLevelGraphicsContext &) Line 571	C++
 	MyApp.vst3!juce::OpenGLContext::CachedImage::paintComponent(const juce::OpenGLContext::CachedImage::AreaAndScale & currentAreaAndScale) Line 520	C++
 	MyApp.vst3!juce::OpenGLContext::CachedImage::renderFrame(juce::MessageManager::Lock & mmLock) Line 407	C++
 	[Inline Frame] MyApp.vst3!juce::OpenGLContext::CachedImage::RenderThread::renderAll() Line 835	C++
 	MyApp.vst3!juce::OpenGLContext::CachedImage::RenderThread::<lambda>() Line 925	C++
 	[External Code]	

And another:

 	ntdll.dll!00007ff86bd130b8()	Unknown
 	ntdll.dll!00007ff86bd11dd7()	Unknown
 	ntdll.dll!00007ff86bd11c9a()	Unknown
 	ucrtbase.dll!00007ff869681a89()	Unknown
>	[Inline Frame] MyApp.vst3!juce::HeapBlock<juce::ReadWriteLock::ThreadRecursionCount,0>::realloc(unsigned __int64 newNumElements, unsigned __int64) Line 292	C++
 	[Inline Frame] MyApp.vst3!juce::ArrayBase<juce::ReadWriteLock::ThreadRecursionCount,juce::DummyCriticalSection>::setAllocatedSizeInternal(int) Line 417	C++
 	MyApp.vst3!juce::ArrayBase<juce::ReadWriteLock::ThreadRecursionCount,juce::DummyCriticalSection>::setAllocatedSize(int numElements) Line 217	C++
 	[Inline Frame] MyApp.vst3!juce::ArrayBase<juce::Rectangle<int>,juce::DummyCriticalSection>::shrinkToNoMoreThan(int maxNumElements) Line 236	C++
 	[Inline Frame] MyApp.vst3!juce::Array<juce::Rectangle<int>,juce::DummyCriticalSection,0>::minimiseStorageAfterRemoval() Line 1117	C++
 	[Inline Frame] MyApp.vst3!juce::Array<juce::Rectangle<int>,juce::DummyCriticalSection,0>::removeInternal(int) Line 1111	C++
 	[Inline Frame] MyApp.vst3!juce::Array<juce::Rectangle<int>,juce::DummyCriticalSection,0>::remove(int) Line 747	C++
 	MyApp.vst3!juce::RectangleList<int>::clipTo(juce::Rectangle<int> rect) Line 358	C++
 	MyApp.vst3!juce::RenderingHelpers::ClipRegions<juce::RenderingHelpers::SoftwareRendererSavedState>::RectangleListRegion::clipToRectangle(juce::Rectangle<int> r) Line 1824	C++
 	MyApp.vst3!juce::RenderingHelpers::SavedStateBase<juce::RenderingHelpers::SoftwareRendererSavedState>::clipToRectangle(juce::Rectangle<int> r) Line 2093	C++
 	MyApp.vst3!juce::RenderingHelpers::StackBasedLowLevelGraphicsContext<juce::RenderingHelpers::SoftwareRendererSavedState>::clipToRectangle(const juce::Rectangle<int> & r) Line 2708	C++
 	[Inline Frame] MyApp.vst3!juce::Graphics::reduceClipRegion(juce::Rectangle<int>) Line 177	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2036	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::Component::paintWithinParentContext(juce::Graphics &) Line 1994	C++
 	MyApp.vst3!juce::Component::paintComponentAndChildren(juce::Graphics & g) Line 2054	C++
 	MyApp.vst3!juce::Component::paintEntireComponent(juce::Graphics & g, bool ignoreAlphaLevel) Line 2113	C++
 	[Inline Frame] MyApp.vst3!juce::OpenGLContext::CachedImage::paintOwner(juce::LowLevelGraphicsContext &) Line 571	C++
 	MyApp.vst3!juce::OpenGLContext::CachedImage::paintComponent(const juce::OpenGLContext::CachedImage::AreaAndScale & currentAreaAndScale) Line 520	C++
 	MyApp.vst3!juce::OpenGLContext::CachedImage::renderFrame(juce::MessageManager::Lock & mmLock) Line 407	C++
 	[Inline Frame] MyApp.vst3!juce::OpenGLContext::CachedImage::RenderThread::renderAll() Line 835	C++
 	MyApp.vst3!juce::OpenGLContext::CachedImage::RenderThread::<lambda>() Line 925	C++
 	[External Code]	

Worth nothing that I’m getting repro of the issues above on FL 21.0.1 [build 3348]. And only there (so far). The other daws and the APH don’t appear to experience this symptom.

And another:

 	ntdll.dll!00007ffc94b1bda2()	Unknown
 	ntdll.dll!00007ffc94b24e7a()	Unknown
 	ntdll.dll!00007ffc94b2515a()	Unknown
 	ntdll.dll!00007ffc94b31155()	Unknown
 	ntdll.dll!00007ffc94accb18()	Unknown
 	ntdll.dll!00007ffc94a4c7aa()	Unknown
 	ntdll.dll!00007ffc94a5bb36()	Unknown
 	KernelBase.dll!00007ffc91ffb363()	Unknown
 	umpdc.dll!00007ffc90d12620()	Unknown
 	powrprof.dll!00007ffc90d32812()	Unknown
 	user32.dll!00007ffc9370b610()	Unknown
 	[Inline Frame] MyApp.vst3!juce::ScopedSuspendResumeNotificationRegistration::{ctor}(HWND__ * window) Line 529	C++
 	MyApp.vst3!juce::HWNDComponentPeer::HWNDComponentPeer(juce::Component & comp, int windowStyleFlags, HWND__ * parent, bool nonRepainting) Line 1733	C++
 	MyApp.vst3!juce::Component::createNewPeer(int styleFlags, void * parentHWND) Line 4691	C++
 	MyApp.vst3!juce::Component::addToDesktop(int styleWanted, void * nativeWindowToAttachTo) Line 703	C++
 	MyApp.vst3!juce::DropShadower::ShadowWindow::ShadowWindow(juce::Component * comp, const juce::DropShadow & ds) Line 53	C++
 	MyApp.vst3!juce::DropShadower::updateShadows() Line 346	C++
 	[Inline Frame] MyApp.vst3!juce::Component::sendVisibilityChangeMessage::__l4::<lambda_ec00523efcf02d27b87029bfc5a24392>::operator()(juce::ComponentListener &) Line 613	C++
>	[Inline Frame] MyApp.vst3!juce::ListenerList<juce::ComponentListener,juce::Array<juce::ComponentListener *,juce::DummyCriticalSection,0>>::callChecked(const juce::Component::BailOutChecker &) Line 170	C++
 	MyApp.vst3!juce::Component::sendVisibilityChangeMessage() Line 613	C++
 	MyApp.vst3!juce::Component::setVisible(bool shouldBeVisible) Line 593	C++
 	MyApp.vst3!juce::PopupMenu::showWithOptionalCallback(const juce::PopupMenu::Options & options, juce::ModalComponentManager::Callback * userCallback, bool) Line 2127	C++
 	[Inline Frame] MyApp.vst3!juce::PopupMenu::showMenuAsync(const juce::PopupMenu::Options &) Line 2163	C++
 	MyApp.vst3!juce::ComboBox::showPopup() Line 549	C++
 	[Inline Frame] MyApp.vst3!juce::InternalMessageQueue::dispatchMessage(juce::MessageManager::MessageBase *) Line 198	C++
 	MyApp.vst3!juce::InternalMessageQueue::dispatchMessages() Line 240	C++
 	MyApp.vst3!juce::InternalMessageQueue::messageWndProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 169	C++
 	[External Code]	

Because we’re seeing unexplainable behavior in a single daw after updating to Juce 7 from early version of 6. The codebase is large, and using something like ASAN to catch oddities and trap api misuse makes sense. (even at this “stage” of development)

Is there a reason you wouldn’t employ tools to control quality at any stage of development? Just curious. :wink:

1 Like

One thing I’ve found when testing with ASAN lately, is that it’s worth doing the plugin scanning/project setup part without ASAN enabled.

I haven’t fully figured this out, but at least on UNIX systems, certain ASAN dynamic libraries have to be preloaded before your module is executed. And this can be a problem if the DAW does plugin scanning in a separate process: your IDE will preload the ASAN libraries for the DAW process, but then the scanning process will not have them, and it will segfault.

It’s been just a couple of weeks since I’ve run plugins with ASAN in FLStudio on Windows, but first I scanned the plugin without ASAN enabled, then rebuilt it with ASAN, and opened it, and it worked fine.

2 Likes

Ah, interesting! I can’t seem to get ASAN working in an x64 process over here on windows, period - at least with VS2019 tools. I was able to get it rolling in an x86 build, so it very well could be a version issue locally, although the latest versions of compilers/toolkits are in place. FL might have an x86 host, but I figured I’d glean what I could with the pluginhost@x86, and then focus on trapping what I could and perhaps digging deeper in the future.

When you tested ASAN + FLStudio on windows, what msvc toolkits were you using?

-M

2022 x64

Yeah, I might have to bite the bullet and give that a shot.

Edit:
I just updated, and everything works. x64 builds w/asan work fine with the 2022 toolkit - they load up in FL without issue - and, low and behold, exposed a buffering issue with some recently-introduced partner DSP.

@reuk - and just like that, all the weird rendering issues evaporated. :slight_smile:

-M

1 Like

I’m not questioning your wisdom, it makes sense in the context of the issues you’re facing, I was just wondering why you found analysis of your project with ASAN is necessary during development and not, say, as an optimization phase once the code has settled … and now I understand, its because you’re chasing bugs in other DAW’s.

I say this as a developer who pretty much has muscle-memory for adding valgrind and coverity stages to his Makefiles … just didn’t think of such tooling in the context of JUCE, yet … :wink:

1 Like