Segfault crash associated with Chronoblob2

A user found this bug and reported it in this thread: Alright Devices Chronoblob2: Please verify this bug and tell me where to report it

I’m using Ubuntu 19.04, Rack 1.1.3, and Alright Devices plugin 1.0.0. I’ve found that I can reproduce the crash by doing the following:

  • Construct a patch consisting only of two instances of Chronoblob2 (not even an audio interface) and no patch cables
  • Delete one of the instances and then attempt to Save As
  • Undo, delete the same instance again, and Save As

This happens both with the binary release and with a freshly built from source version running in a gdb session.

I’m no expert on desktop software development but as far as I can tell it’s not actually crashing from my plugin’s code. Rather, it looks like the crash is deeply nested within a call to rack::Window::run(). However, it is definitely associated with the presence of two Chronoblob2 instances. I tried the same thing with two instances of T-Wrex, and two instances of some Fundamental module but could not make it crash.

Here’s my gdb backtrace:

#0  0x00007ffff72061ed in __GI___libc_free (mem=0x16) at malloc.c:3109
#1  0x00007fffd80c3ac9 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#2  0x00007fffd80c4588 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#3  0x00007fffd80c4516 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#4  0x00007fffd80c4490 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#5  0x00007fffd80c4516 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#6  0x00007fffd80c4516 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#7  0x00007fffd80c4516 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#8  0x00007fffd80c4516 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#9  0x00007fffd80c4490 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#10 0x00007fffd80c4490 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#11 0x00007fffd80a28d5 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#12 0x00007fffd8093f87 in  () at /lib/x86_64-linux-gnu/librsvg-2.so.2
#13 0x00007ffff77ddf93 in g_object_unref () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#14 0x00007fffe8120408 in  () at /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.so
#15 0x00007ffff6c119a3 in gdk_pixbuf_loader_close () at /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
#16 0x00007ffff6c0e32b in  () at /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
#17 0x00007ffff6c0f24d in gdk_pixbuf_new_from_stream_at_scale () at /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
#18 0x00007ffff7923a09 in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#19 0x00007ffff7926b2a in gtk_icon_info_load_icon () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#20 0x00007ffff7926ca6 in gtk_icon_theme_load_icon () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#21 0x00007ffff7900e77 in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#22 0x00007ffff79011d8 in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#23 0x00007ffff7902a0c in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#24 0x00007ffff77d8e8d in g_closure_invoke () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#25 0x00007ffff77ebdad in  () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#26 0x00007ffff77f54ae in g_signal_emit_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#27 0x00007ffff77f5b6f in g_signal_emit () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#28 0x00007ffff7a6b89c in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#29 0x00007ffff78a52c5 in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#30 0x00007ffff7a6b8cf in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#31 0x00007ffff7a6e2a3 in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#32 0x00007ffff7a7349a in gtk_widget_set_parent () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#33 0x00007ffff78a5ee4 in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#34 0x00007ffff7907fbe in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#35 0x00007ffff77de562 in  () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#36 0x00007ffff77e05c4 in g_object_new_valist () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#37 0x00007ffff77e08f9 in g_object_new () at /lib/x86_64-linux-gnu/libgobject-2.0.so.0
#38 0x00007ffff79083bd in  () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#39 0x00007ffff79084ca in gtk_file_chooser_dialog_new () at /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
#40 0x000055555579641c in osdialog_file
    (action=action@entry=OSDIALOG_SAVE, path=0x7fffffffd730 "./patches", filename=0x7fffffffd750 "", filters=filters@entry=0x5555566e7000) at dep/osdialog/osdialog_gtk2.c:71
#41 0x000055555571df17 in rack::PatchManager::saveAsDialog() (this=0x5555563aa7e0) at /usr/include/c++/8/bits/basic_string.h:2290
#42 0x000055555576ebc3 in rack::app::Scene::onHoverKey(rack::event::HoverKey const&) (this=0x5555563ce7f0, e=...)
    at src/app/Scene.cpp:93
#43 0x0000555555746536 in rack::event::State::handleKey(rack::math::Vec, int, int, int, int)
    (this=<optimized out>, pos=..., key=<optimized out>, 
    key@entry=83, scancode=scancode@entry=39, action=action@entry=1, mods=mods@entry=35) at /usr/include/c++/8/bits/stl_iterator.h:133
#44 0x000055555574077b in rack::keyCallback(GLFWwindow*, int, int, int, int)
    (win=<optimized out>, key=83, scancode=39, action=1, mods=35) at src/window.cpp:172
#45 0x00005555557a67e5 in processEvent (event=0x7fffffffd9f0) at /tyler/repos/Rack/dep/glfw/src/x11_window.c:1264
#46 0x00005555557a67e5 in _glfwPlatformPollEvents () at /tyler/repos/Rack/dep/glfw/src/x11_window.c:2698
#47 0x000055555579e9ff in glfwPollEvents () at /tyler/repos/Rack/dep/glfw/src/window.c:1070
#48 0x00005555557409b2 in rack::Window::run() (this=0x555555c70600) at src/window.cpp:327
#49 0x00005555556bd8cc in main(int, char**) (argc=<optimized out>, argv=<optimized out>) at src/main.cpp:186

And my log.txt with the stack trace at the end:

[0.000 info src/main.cpp:113] VCV Rack v1.1.3
[0.000 info src/main.cpp:114] Linux 5.0.0-20-generic #21-Ubuntu SMP Mon Jun 24 09:32:09 UTC 2019 x86_64
[0.000 info src/main.cpp:120] Args: ./Rack 
[0.000 info src/main.cpp:123] System directory: .
[0.000 info src/main.cpp:124] User directory: /home/tyler/.Rack
[0.000 info src/settings.cpp:213] Loading settings /home/tyler/.Rack/settings-v1.json
[0.000 info src/main.cpp:146] Initializing environment
[0.034 info src/plugin.cpp:157] Loaded plugin Core v1.1.3 from 
[0.035 info src/plugin.cpp:157] Loaded plugin AlrightDevices v1.0.0 from /home/tyler/.Rack/plugins-v1/AlrightDevices
[0.037 info src/plugin.cpp:157] Loaded plugin AudibleInstruments v1.0.0 from /home/tyler/.Rack/plugins-v1/AudibleInstruments
[0.038 info src/plugin.cpp:157] Loaded plugin Befaco v1.0.0 from /home/tyler/.Rack/plugins-v1/Befaco
[0.038 info src/plugin.cpp:157] Loaded plugin ESeries v1.0.0 from /home/tyler/.Rack/plugins-v1/ESeries
[0.040 info src/plugin.cpp:157] Loaded plugin Fundamental v1.0.1 from /home/tyler/.Rack/plugins-v1/Fundamental
[0.048 info src/main.cpp:161] Initializing app
[0.134 info src/bridge.cpp:382] Bridge server started
[0.173 info src/window.cpp:227] Window content scale: 1.000000
[0.245 info src/window.cpp:267] Renderer: AMD PITCAIRN (DRM 2.50.0, 5.0.0-20-generic, LLVM 8.0.0)
[0.245 info src/window.cpp:268] OpenGL: 4.5 (Compatibility Profile) Mesa 19.0.2
[0.246 info src/window.cpp:33] Loaded font ./res/fonts/DejaVuSans.ttf
[0.247 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/RackBusboard.svg
[0.247 info src/settings.cpp:196] Saving settings /home/tyler/.Rack/settings-v1.json
[0.699 warn src/plugin.cpp:424] VCV account has plugin Grayscale but no manifest was found
[1.372 info src/patch.cpp:161] Loading patch /home/tyler/.Rack/autosave-v1.vcv
[1.383 info src/window.cpp:72] Loaded SVG /home/tyler/.Rack/plugins-v1/AlrightDevices/res/chronoblob2.svg
[1.383 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/ScrewSilver.svg
[1.383 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/Rogan1PSWhite.svg
[1.383 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/Rogan3PSWhite.svg
[1.384 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/Trimpot.svg
[1.384 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/PJ301M.svg
[1.384 info src/window.cpp:72] Loaded SVG /home/tyler/.Rack/plugins-v1/AlrightDevices/res/PB6149L-off.svg
[1.384 info src/window.cpp:72] Loaded SVG /home/tyler/.Rack/plugins-v1/AlrightDevices/res/SSSF012100-left.svg
[1.384 info src/window.cpp:72] Loaded SVG /home/tyler/.Rack/plugins-v1/AlrightDevices/res/SSSF012100-right.svg
[1.384 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/TL1105_0.svg
[1.384 info src/window.cpp:72] Loaded SVG ./res/ComponentLibrary/TL1105_1.svg
[1.385 info src/main.cpp:173] Starting engine
[1.385 info src/main.cpp:185] Running window
[5.554 fatal src/main.cpp:38] Fatal signal 11. Stack trace:
47: ./Rack() [0x56d951]
46: /lib/x86_64-linux-gnu/libc.so.6(+0x43f60) [0x7f6f46033f60]
45: /lib/x86_64-linux-gnu/libc.so.6(cfree+0x1d) [0x7f6f460891ed]
44: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xa9ac9) [0x7f6eed599ac9]
43: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa588) [0x7f6eed59a588]
42: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa516) [0x7f6eed59a516]
41: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa516) [0x7f6eed59a516]
40: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa516) [0x7f6eed59a516]
39: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa516) [0x7f6eed59a516]
38: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa516) [0x7f6eed59a516]
37: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa516) [0x7f6eed59a516]
36: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa490) [0x7f6eed59a490]
35: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0xaa490) [0x7f6eed59a490]
34: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0x888d5) [0x7f6eed5788d5]
33: /lib/x86_64-linux-gnu/librsvg-2.so.2(+0x79f87) [0x7f6eed569f87]
32: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_unref+0x113) [0x7f6f46678f93]
31: /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.so(+0x1408) [0x7f6f18291408]
30: /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0(gdk_pixbuf_loader_close+0x103) [0x7f6f45a779a3]
29: /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0(+0xc32b) [0x7f6f45a7432b]
28: /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0(gdk_pixbuf_new_from_stream_at_scale+0x7d) [0x7f6f45a7524d]
27: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(+0x102a09) [0x7f6f467c2a09]
26: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(gtk_icon_info_load_icon+0x4a) [0x7f6f467c5b2a]
25: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(gtk_icon_theme_load_icon+0xe6) [0x7f6f467c5ca6]
24: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(+0xdfe77) [0x7f6f4679fe77]
23: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(+0xe5a7a) [0x7f6f467a5a7a]
22: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(+0x19562) [0x7f6f46679562]
21: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_new_with_properties+0x2f5) [0x7f6f4667aeb5]
20: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_new+0xc1) [0x7f6f4667b921]
19: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(+0xea2a4) [0x7f6f467aa2a4]
18: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(+0x19562) [0x7f6f46679562]
17: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_new_with_properties+0x2f5) [0x7f6f4667aeb5]
16: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_new+0xc1) [0x7f6f4667b921]
15: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(+0xe6fec) [0x7f6f467a6fec]
14: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(+0x19562) [0x7f6f46679562]
13: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_new_valist+0x3f4) [0x7f6f4667b5c4]
12: /lib/x86_64-linux-gnu/libgobject-2.0.so.0(g_object_new+0x99) [0x7f6f4667b8f9]
11: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(+0xe73bd) [0x7f6f467a73bd]
10: /lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0(gtk_file_chooser_dialog_new+0x8a) [0x7f6f467a74ca]
9: ./Rack(osdialog_file+0x8e) [0x5be31a]
8: ./Rack(_ZN4rack12PatchManager12saveAsDialogEv+0x113) [0x540535]
7: ./Rack(_ZN4rack3app5Scene10onHoverKeyERKNS_5event8HoverKeyE+0x28a) [0x5a8e0e]
6: ./Rack(_ZN4rack5event5State9handleKeyENS_4math3VecEiiii+0x1dd) [0x56cdb3]
5: ./Rack() [0x566498]
4: ./Rack(_glfwPlatformPollEvents+0xbe7) [0x5cf4f0]
3: ./Rack(_ZN4rack6Window3runEv+0x69) [0x5666bb]
2: ./Rack(main+0x45a) [0x4e6e1a]
1: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb) [0x7f6f46016b6b]
0: ./Rack(_start+0x29) [0x4ebd49]

Does anyone have any idea what might be causing this? I’m really quite stumped :thinking::thinking::thinking:

It’s a bit hard to track this down without access to the source, but I’ll try: running Rack with a debugger I get a segmentation fault if I delete any second instance of Chronoblob2. It happens while deconstructing module’s widget, so my guess is that in the deconstructor of Chronoblob2’s widget is something deleted that shouldn’t. Can you check that?

There’s not really enough to point to the cause, but bizarre crashes that follow a specific sequence of events but aren’t directly related to those events often mean memory corruption. Run it under Valgrind and you might find it points you to the problem.

I’ve seen crashes like this in other software,and it looks like memory allocation problems. Probably a double free.

Use Valgrind to get a comprehensive look at memory errors. It will show the memory errors that lead up to the crash.

Just guessing, but if the crash is down in the SVG library, you’re not managing resources shared between module instances correctly.

my obvious guess:
it’s a global/singleton allocated in global space at the first use and deallocate in the destructor without setting at least to NIL the pointer : other instances still using it crash

Thank you all for the suggestions! I’m running valgrind right now but it sure is slow. I’ll follow up with those results.

@stoermelder My widget doesn’t define a destructor, so it should just have the empty one inherited from ModuleWidget right?

@chaircrusher @synthi There’s only one place where I’ve used dynamic memory, and it isn’t shared between instances. It’s in the following class. Have I screwed up the memory management?

template <typename T>
class RamMemory
{
private:
    T *buffer_;
    uint32_t buffer_size_;
    uint32_t head_;

public:
    RamMemory()
    {
        buffer_ = NULL;
    }

    ~RamMemory()
    {
        delete[] buffer_;
    }

    void Init(uint32_t size, uint32_t initial_head_position = 0)
    {
        delete[] buffer_;
        buffer_ = new T[size];
        buffer_size_ = size;
        head_ = initial_head_position;
        memset(buffer_, 0, buffer_size_ * sizeof(T));
    }

    void Write(T *source, uint32_t length)
    {
        if (head_ + length <= buffer_size_)
        {
            memcpy(&buffer_[head_], source, length * sizeof(T));

            head_ += length;
            head_ %= buffer_size_;
        }
        else
        {
            uint32_t length_a = buffer_size_ - head_;
            uint32_t length_b = length - length_a;

            memcpy(&buffer_[head_], source, length_a * sizeof(T));
            memcpy(buffer_, &source[length_a], length_b * sizeof(T));

            head_ = length_b;
        }
    }

    void Read(T *dest, uint32_t delay, uint32_t length)
    {
        uint32_t offset = head_;

        if (head_ < delay)
        {
            offset += buffer_size_;
        }

        offset -= delay;

        if (offset + length <= buffer_size_)
        {
            memcpy(dest, &buffer_[offset], length * sizeof(T));
        }
        else
        {
            uint32_t length_a = buffer_size_ - offset;
            uint32_t length_b = length - length_a;

            memcpy(dest, &buffer_[offset], length_a * sizeof(T));
            memcpy(&dest[length_a], buffer_, length_b * sizeof(T));
        }
    }
};

seems correct, only problem is not thread safe: one thread could be writing when another one (the owner of the object) is calling the destructor

But I guess this is all in the engine thread

Wouldn’t that class also have problems if you copied it (since the copy would copy the pointer and delete it twice) and also if you never called init on one, in which case it would delete[] null? Or am I misreading the code?

Here’s a modified version of the RamMemory code in an example which does the double free and, on my mac, shows a pretty clear memory error

#include <iostream>

template <typename T>
class RM
{
private:
   T *b;
public:
   RM() { b = nullptr; }
   ~RM() { 
     std::cout << "Deleting memory at " << (size_t)b << std::endl;
     delete[] b; 
   }
   void init() {
     b = new T[123];
   }
};

int main(int argc, char **argv)
{
  {
    RM<float> B; B.init();
  }
  {
    // Will delete NULL
    RM<float> B; 
  }
  {
    RM<float> B; B.init(); RM<float> C; C = B;
    // Will double delete.
  }
}

Pretty easy to fix, though, if you just #include <memory> and make T* buffer_ a std::shared_ptr<T> buffer_ or what not.

Deleting a null pointer has no effect. That makes sense about the double deletion but I’m not copying this class anywhere.

I tried running under valgrind but I gave up after a couple days. I know it’s supposed to run slowly but it took literal hours just to finish drawing the 2 modules in my patch. Is that normal?

if you’re using clang++ or g++ 4.8 or higher you can add -fno-omit-frame-pointer -fsanitize=address to your flags, which will do run-time checking.

Should I use those flags to compile Rack or my plugin? Or both? I tried compiling the plugin with them but then Rack could not find any modules in the plugin.

your plugin, but depending on your OS, you might need to dyload some libraries when it runs. check the output of your logs when you ./Rack -d.