C external crashing with __stack_chk_fail / __abort / __pthread_kill

adamflorin's icon

A C external I've built periodically crashes, with the following stack trace.

Thread 3 Crashed:: AudioCalc
0   libsystem_kernel.dylib            0x9567269a __pthread_kill + 10
1   libsystem_pthread.dylib           0x984d8f19 pthread_kill + 101
2   libsystem_c.dylib                 0x96f89fba __abort + 187
3   libsystem_c.dylib                 0x96f8a83a __stack_chk_fail + 239
4   com.cycling74.segmentgenerator    0x1e09e701 segmentgenerator_output_segment + 945
...

segmentgenerator_output_segment doesn't do much except output (outlet_anything) a message which includes the contents of a passed-in t_atomarray * (using atomarray_getatoms and a bunch of atom_set* to copy the fields over one atom at a time). I can share the source of that one function if that would be helpful.

More generally, does anyone know what's happening here? At a glance, it appears that a stack overflow has been detected—but where?—and that the entire thread is being killed, which brings down the entire application.

Luigi Castelli's icon

Hi Adam,
there is a myriad of things that might have gone wrong and therefore generated the error you are seeing.
You can try sharing only that one function, but it might be of no use.
The best approach to solve your issue would be looking at the source code in its entirety.
(also next time it would be better for you to use the Dev section for this kind of questions)

- Luigi

adamflorin's icon

Thanks, Luigi. I've re-filed this topic in the "Dev" forum. The C source for this file is quite enormous (almost 1k lines), so I'm resisting spamming the group. I'm mainly wondering if there are any major red flags I should be looking out for!

Emmanuel Jourdan's icon

I would just make sure that the data your reading in this segmentgenerator_output_segment isn't changed in another thread at the same time.

adamflorin's icon

Thanks, Emmanuel! Based on the C source, the external should only be touching memory within its own struct (unless the output data gets modified downstream—?). I'm studying the other threads in the crash log, but don't see what else it could be. But I'll keep digging!

Joshua Kit Clayton's icon

FWIW, I’d recommend you post the complete crash log (or link to a pastebin), and if you have them, a simple patch which reproduces, and if possible, the function call source if not the whole file.

However, this sort of thing typically happens when there are many nested function calls and/or allocating large amounts of memory on the stack inside your c functions (e.g. statically defining huge arrays of atoms at the top of your function rather than allocating them dynamically with sysmem_newptr or similar). In such a case, you will run out of stack memory, generating such exceptions.

adamflorin's icon

Thanks, Joshua!

Short answer: I didn't know about the "sysmem" API. I may just try rewriting my many static array definitions to use that, and cross my fingers.

This issue is very hard to reproduce, even when heavily stress-testing my application. It tends to creep up unexpectedly after a longer duration of use.

Here's a full OSX crashlog:

And the crashing function:

void segmentgenerator_output_segment(t_segmentgenerator * x, t_atomarray *segment, t_symbol *parameter) {
t_max_err error;
long segment_length;
t_atom *segment_atoms;
t_atom segment_message[13];
int note;
error = atomarray_getatoms(segment, &segment_length, &segment_atoms);
if (error) {
object_error((t_object *)x, "Error fetching last past segment atoms. (%d)", error);
return;
}
atom_setsym(segment_message + 0, x->ui_symbol);
atom_setsym(segment_message + 1, x->parameter_symbol);
atom_setsym(segment_message + 2, parameter);
atom_setfloat(segment_message + 3, atom_getfloat(segment_atoms + 0));
atom_setfloat(segment_message + 4, atom_getfloat(segment_atoms + 1));
atom_setlong(segment_message + 5, atom_getlong(segment_atoms + 2));
atom_setlong(segment_message + 6, atom_getlong(segment_atoms + 3));
atom_setlong(segment_message + 7, atom_getlong(segment_atoms + 4));
atom_setlong(segment_message + 8, atom_getlong(segment_atoms + 5));
for (note = 0; note < atom_getlong(segment_atoms + 2); note++) {
atom_setlong(segment_message + 9 + note, atom_getlong(segment_atoms + 6 + note));
}
outlet_anything(x->outlet, gensym("direct"), 9+atom_getlong(segment_atoms + 2), segment_message);
}

In case it's relevant, the crashing thread always begins with an itm callback in one of my externals (sequencer) and crashes in another one (segmentgenerator).

adamflorin's icon

Oh jeez, I can see in Activity Monitor that my M4L device is gobbling up memory at a rate of 10s of MBs per minute (during stress testing), which is not freed until the device is removed. Looks like a smoking gun if I've ever seen one! Now to figure out when it's safe to free all that stuff... I've been spoiled by GC too long.