Segfault crash associated with Chronoblob2

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.

Well I finally had time to chase down this bug. Turns out @synthi was exactly right. I had one global that I was using to store a pointer. Simply replaced it with a class member and no more crashing! The commit diff was like 2 lines, lmao. Embarrassing :stuck_out_tongue:

Anyway thank you so much everyone for your help and suggestions!

13 Likes

Hi @AlrightDevices, I think I’ve got a similar issue in a plugin I’ve just been testing.

If it’s okay could you please copy those commit diff lines into this thread? I’m struggling to fully grasp what your solution was. I’m hoping it will be a similar fix for my plugin!

Cheers.

I don’t think the commit diff by itself will help. It’s better if I just describe the problem and solution.

I have a class called Interface whose source is split into an .h file and a .cpp file. My Module class contains a member of type Interface. Interface has no static members, but there was a global variable instantiated in the .cpp file, separate from the class.

Interface was using that variable to store a pointer to another member of its owner Module during initialization, and to dereference later during runtime. Since the pointer was global, it was shared between instances of Interface, and therefore also between instances of Module.

So, consider this sequence of events:

  • Instantiate a Module called module1. Now global_pointer contains the address of module1.other_member. Everything is fine.

  • Instantiate a Module called module2. Now global_pointer contains the address of module2.other_member. Both module1.interface and module2.interface are dereferencing a pointer to module2.other_member. This is not good but it probably won’t cause a crash, although it might cause some weird interaction between the two instances. In my case it didn’t have any effect because of the nature and purpose of other_member.

  • Destruct module2. Now module1.interface is still dereferencing a pointer to module2.other_member, which has been deallocated. Oops!

The solution is simple, just get rid of the global variable and store the pointer in a member variable instead.

Hope that helps! Good luck!

3 Likes

Much appreciated! Hmmm, i think I’ve removed all global pointers. I do have some 2d vectors… perhaps it is them?

The process you outline to replicate your crash works for me so I reckon I’m on the right track…

I’ll keep digging :slight_smile:

2 Likes

@AlrightDevices - Hi Tyler,

I’ve been playing around with your plugin. Really love it.

One interesting thing I’ve noticed is that when I use my plugin in tandem with others, occasionally it will cause rendering to mess up on multiple plugins, including itself… This may well be a separate issue from what I’ve been attempting to troubleshoot but I thought I’d post a screenshot to see if it rings any bells in what you’ve worked though. This is how your Chronoblob2 is affected:

Again, I’m almost certain it is my plugin causing this graphical tearing effect on yours somehow…

It is less obvious on my plugin due to the colours I’ve used but it’s still there. (tear of block colour from top left to the bottom right):

If this is not something you’ve seen before then not to worry. Just mildly hopeful that it may somehow correlate with the saving/segfault that my module is still suffering from.

Cheers, Alex

I saw this once before in a stoemelder plug :

And @stoermelder knew what to do, maybe its related ?

1 Like

Thanks @Yeager, I’ll follow the link shortly. :crossed_fingers::+1:

I had an array-out-of-bounds access in my module that caused visual destruction…

1 Like

Sorry, I’ve got no idea what might be causing that. Never seen it happen before.