UB in juce::Rectangle::leftTopRightBottom

I’m getting some undefined behaviour in the aforementioned function. This happens when right is INTMAX and left is INTMIN, which in itself is of course incorrect.

AFAICT this happens when it’s called from juce::ComponentPeer::handlePaint because the context there has a complexTransform with both mat00 and mat11 set to +Inf. When this is then inverted, it results in NaNs all around. These are then either put through floorAsInt and ceilAsInt, turning them into INTMIN and INTMAX, respectively.

This is happening on JUCE 5.4.7, btw. I’m quite new to JUCE, so I’m unsure whether the issue is those +Inf values in mat00 and mat11 or whether this is expected behaviour.

Please let me know if there is more information you need. The callstack is as follows:

* thread #1, name = 'App', stop reason = breakpoint 1.1
    frame #0: 0x0000000004207cb4 App`juce::Rectangle<int>::leftTopRightBottom(left=-2147483648, top=-2147483648, right=2147483647, bottom=2147483647) at juce_Rectangle.h:83:18
    frame #1: 0x00000000041a2f57 App`juce::Rectangle<float>::getSmallestIntegerContainer(this=0x00007fffffffdc40) const at juce_Rectangle.h:814:16
    frame #2: 0x0000000004212d69 App`juce::Rectangle<float>::copyWithRounding(this=0x00007fffffffdc40, result=0x00007fffffffdc90) const at juce_Rectangle.h:973:81
    frame #3: 0x0000000004212d2b App`juce::Rectangle<int>::transformedBy(this=0x00007fffffffdce0, transform=0x00007fffffffdcb8) const at juce_Rectangle.h:804:63
    frame #4: 0x0000000004213a96 App`juce::Rectangle<int> juce::RenderingHelpers::TranslationOrTransform::deviceSpaceToUserSpace<int>(this=0x0000000011b535a8, r=Rectangle<int> @ 0x00007fffffffdce0) const at juce_RenderingHelpers.h:133:37
  * frame #5: 0x00000000042139f0 App`juce::RenderingHelpers::SavedStateBase<juce::RenderingHelpers::SoftwareRendererSavedState>::getClipBounds(this=0x0000000011b535a0) const at juce_RenderingHelpers.h:2200:44
    frame #6: 0x00000000041aac61 App`juce::RenderingHelpers::StackBasedLowLevelGraphicsContext<juce::RenderingHelpers::SoftwareRendererSavedState>::getClipBounds(this=0x0000000011adab90) const at juce_RenderingHelpers.h:2689:98
    frame #7: 0x000000000415d91d App`juce::Graphics::getClipBounds(this=0x00007fffffffe118) const at juce_GraphicsContext.cpp:127:20
    frame #8: 0x000000000421dfa7 App`juce::Component::paintComponentAndChildren(this=0x000000001046c2c8, g=0x00007fffffffe118) at juce_Component.cpp:1897:25
    frame #9: 0x000000000421df62 App`juce::Component::paintEntireComponent(this=0x000000001046c2c8, g=0x00007fffffffe118, ignoreAlphaLevel=true) at juce_Component.cpp:2005:9
    frame #10: 0x00000000042b55d5 App`juce::ComponentPeer::handlePaint(this=0x000000001046c630, contextToPaintTo=0x0000000011adab90) at juce_ComponentPeer.cpp:133:19
    frame #11: 0x000000000435430d App`juce::LinuxComponentPeer::LinuxRepaintManager::performAnyPendingRepaintsNow(this=0x0000000010463ad0) at juce_linux_X11_Windowing.cpp:2357:26
    frame #12: 0x0000000004353ddd App`juce::LinuxComponentPeer::LinuxRepaintManager::timerCallback(this=0x0000000010463ad0) at juce_linux_X11_Windowing.cpp:2296:17
    frame #13: 0x0000000004141a8b App`juce::Timer::TimerThread::callTimers(this=0x00000000048ffd40) at juce_Timer.cpp:114:24
    frame #14: 0x00000000041419ac App`juce::Timer::TimerThread::CallTimersMessage::messageCallback(this=0x00007ffee8000b40) at juce_Timer.cpp:180:27
    frame #15: 0x0000000004145a8e App`juce::InternalMessageQueue::InternalMessageQueue(this=0x00000000047ae3b8, fd=4)::'lambda'(int)::operator()(int) const at juce_linux_Messaging.cpp:43:62
    frame #16: 0x0000000004145911 App`std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(__functor=0x00000000047ae3b8, __args=0x00007fffffffe564) at std_function.h:297:2
    frame #17: 0x00000000028ac904 App`std::function<void (int)>::operator(this=0x00000000047ae3b8, __args=4)(int) const at std_function.h:687:14
    frame #18: 0x000000000413ec3a App`juce::InternalRunLoop::dispatchPendingEvents(this=0x0000000004808840) at juce_linux_Messaging.cpp:169:21
    frame #19: 0x0000000004134bdf App`juce::MessageManager::dispatchNextMessageOnSystemQueue(returnIfNoPendingMessages=false) at juce_linux_Messaging.cpp:260:26
    frame #20: 0x000000000413423b App`juce::MessageManager::runDispatchLoop(this=0x00000000048ef9a0) at juce_MessageManager.cpp:133:19
    frame #21: 0x000000000413419b App`juce::JUCEApplicationBase::main() at juce_ApplicationBase.cpp:262:40
    frame #22: 0x000000000413409d App`juce::JUCEApplicationBase::main(argc=1, argv=0x00007fffffffe7e8) at juce_ApplicationBase.cpp:240:16
    frame #23: 0x00000000028890e3 App`main(argc=1, argv=0x00007fffffffe7e8) at main.cpp:6:1
    frame #24: 0x00007fffedbba09b libc.so.6`__libc_start_main(main=(App`main at main.cpp:6), argc=1, argv=0x00007fffffffe7e8, init=<unavailable>, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffe7d8) at libc-start.c:308:16
    frame #25: 0x00000000027d296a App`_start + 42

Welcome on the forum!

It would be interesting how it came to that situation. Calling operations with +Inf or NaN involved is undefined behaviour already. The question is, how did the complexTransform end up degraded?

Did you call code that sets the transformation? It seems like a zoom calculation gone wrong.

Anything you can provide to recreate that situation would be helpful.

Thanks for the quick reply, daniel.

I’m not directly calling code to set the transform. It seems it only happens early on in the app startup. Later drawing operations succeed just fine. It doesn’t seem to cause any real issues, besides the fact that it gets flagged as UB during runtime.

Could it be that the values are initially undefined until JUCE reads the proper screen dimensions later on?

Sorry for not answering sooner.
I don’t have a linux at hand to test at the moment.
Maybe somebody else could chime in?

And could you maybe test with the latest juce again, so the juce team doesn’t hunt old bugs?
I think there went some work into the linux part lately.

Sure. I’ll see if I can reproduce it with the JUCE examples on with the latest release.