Crash when calling String( CharPointer_UTF8(char[]) )


#1

I searched the forum, but couldn’t find a recent topic where this might have been covered. Sorry if it’s a known problem.

The crash happens when calling vst_processor_instance->getParameterText(0) for the FMMF VSTi plugin. FMMF is a popular free vst instrument found here: https://delamanchavst.wordpress.com/2013/10/18/fmmf/

Granted, FMMF returns some characters which looks garbled for effect 0, but it’s probably a bug in JUCE that the constructor of juce::String crashes. This diff avoids the crash:

— a/pluginhost/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
+++ b/pluginhost/JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
@@ -1755,7 +1755,8 @@ private:
jassert (index >= 0 && index < effect->numParams);
char nm [256] = { 0 };
dispatch (opcode, index, 0, nm, 0);

  •    return String (CharPointer_UTF8 (nm)).trim();
    
  •    return String::empty;
    
  •    //return String (CharPointer_UTF8 (nm)).trim();
    
    }

My JUCE tree is from 15. January this year, so the bug might have been fixed since then. I’m compiling JUCE with i686-w64-mingw32.static-g++ (GCC) 4.9.3 from mxe.


#2

I’ve checked that it’s not the call to trim() that’s causing the crash.


#3

Here’s the code that crashes:

const char crash[] = {3,1,1,1,1,-128,-128,-128,-128,16,1,1,1,1,1,77,26,52,
111,4,77,26,52,111,4,1,1,1,1,1,1,0};
String(CharPointer_UTF8(crash));

Those numbers are the actual characters returned by FMMF for effect number 2.
(effect number 0 suddenly didn’t cause crash, don’t know what happened, but
at least effect number 2 crashed)


#4

Are you confusing a crash with an assertion?


#5

Maybe, but I don’t think so. If that is the case then the following two conditions must be true:

  1. Either assertions are enabled in release mode, or I accidentally compile in debug mode when I was supposed to compile in release mode.
  2. When hitting an assert (at least when compiled with mingw), my exception handler (installed by using SetUnhandledExceptionFilter) is not called. In addition, the windows crash reporter (don’t know what it’s called and I can’t test it right now) kicks in after about ten seconds of silence, asking me about whether I want to send this crash to Microsoft.

But I haven’t tried running the above code in Linux, where I have a lot more control over what happens, so I’ll see what happens then. (can’t test right now though).


#6

Okay, now I’m running on Linux. And this definitely does not look like an assertion:

*** glibc detected *** /home/kjetil/radium/bin/radium: free(): invalid next size (fast): 0x0000000002b68720 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3b4947c00e]
/home/kjetil/radium/bin/radium[0xd9f330]
/home/kjetil/radium/bin/radium[0xd9f366]
/home/kjetil/radium/bin/radium[0xd5c487]
/home/kjetil/radium/bin/radium[0xce416e]
/home/kjetil/radium/bin/radium[0x823d03]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x3b49421735]
/home/kjetil/radium/bin/radium[0x441a61]

(gdb) bt
0 0x0000003b49435935 in raise () from /lib64/libc.so.6
1 0x0000003b494370e8 in abort () from /lib64/libc.so.6
2 0x0000003b49474e8b in __libc_message () from /lib64/libc.so.6
3 0x0000003b4947c00e in _int_free () from /lib64/libc.so.6
4 0x0000000000d9f330 in juce::StringHolder::release (b=0x2b68720) at …/…/JuceLibraryCode/modules/juce_core/text/juce_String.cpp:170
5 0x0000000000d9f366 in juce::StringHolder::release (text=…) at …/…/JuceLibraryCode/modules/juce_core/text/juce_String.cpp:175
Python Exception <type ‘exceptions.RuntimeError’> maximum recursion depth exceeded:
6 0x0000000000d5c487 in juce::String::~String (this=0x7fffffffd540, __in_chrg=) at …/…/JuceLibraryCode/modules/juce_core/text/juce_String.cpp:249
7 0x0000000000ce416e in PLUGINHOST_init () at …/…/…/audio/Juce_plugins.cpp:1240
8 0x0000000000823d03 in main (argc=1, argv=0x7fffffffdaa8) at Qt/Qt_Main.cpp:1317

juce_String.cpp:170 is the delete-line in this function:

static inline void release (StringHolder* const b) noexcept
{
    if (b != (StringHolder*) &emptyString)
        if (--(b->refCount) == -1)
            delete[] reinterpret_cast<char*> (b);
}

#7

If the string destructor crashes because of a memory error, then you must be deleting a dangling pointer. Try writing some standalone test code to reproduce the error and you might see where you’ve gone wrong.


#8

No, I’ve done that. As I wrote above, the code causing this crash is this:

const char crash[] = {3,1,1,1,1,-128,-128,-128,-128,16,1,1,1,1,1,77,26,52,
111,4,77,26,52,111,4,1,1,1,1,1,1,0};
String(CharPointer_UTF8(crash));


#9

OK, well you’re feeding it some garbage and telling it that it’s correctly-formatted UTF8, so when it parses it, expecting UTF8, it goes beyond the end of the data you gave it… Not really a juce bug. If you wrap some data in CharPointer_UTF8 then your should either know for sure that it’s really UTF8, or call CharPointer_UTF8::isValidString on it to check, if it’s external data that could contain errors.


#10

Okay, but this is not my code. This is pulled out of juce_VSTPluginFormat.cpp. Guess it should call isValidString before trying to create a String. (see first post)


#11

Ah… sorry, should have re-read your first post. OK, looks like that plugin must be returning a really long and string of non-UTF8… Thanks, I’ll add some extra safeguards around that.


#12

It looks like isValidString doesn’t work. The following program:

int main(){
const char crash[] = {3,1,1,1,1,-128,-128,-128,-128,16,1,1,1,1,1,77,26,52,
111,4,77,26,52,111,4,1,1,1,1,1,1,0};
printf(“is_valid: %d\n”,CharPointer_UTF8::isValidString(CharPointer_UTF8(crash),strlen(crash)));
return 0;
}

prints out this:

[kjetil@ttlush test] ./a.out JUCE v4.1.0 is_valid: 1 [kjetil@ttlush test]

Or, that the characters are valid, but there is a bug in the String constructor.