SIGSEGV debugging: Where is the update() method defined in cocos2d-iphone? - ios

I am trying to tackle a SIGSEGV signal error in cocos2d-iphone 1.0.1. I must note that, despite several hours trying, I couldn't actually replicate the crash. I only know that it happens because of the testers.
I've collected as much info as I could. First of all, here is the TestFlight backtrace:
Great. So let's take a look at CCScheduler's tick method. It is fairly large, so I have here only the block of code where the error occurs (at the bottom of the question you can see the full method):
for( elt->timerIndex = 0; elt->timerIndex < elt->timers->num; elt->timerIndex++) {
elt->currentTimer = elt->timers->arr[elt->timerIndex];
elt->currentTimerSalvaged = NO;
impMethod( elt->currentTimer, updateSelector, dt);
if( elt->currentTimerSalvaged ) {
[elt->currentTimer release];
}
elt->currentTimer = nil;
}
And the exact error line is
impMethod( elt->currentTimer, updateSelector, dt);
Good. So we got the culprit line.
Let's see, impMethod is of type TICK_IMP, which is defined as
typedef void (*TICK_IMP)(id, SEL, ccTime);
Hm. I don't see any problem with impMethod( elt->currentTimer, updateSelector, dt) itself.
Looking closely, my best guess is that elt->currentTimer could be problematic.
At first, I thought that maybe if elt is a NULL pointer, calling elt->currentTimer could cause a segmentation fault. However, I've recently been told that even if elt was NULL, sending a message to it wouldn't cause a SIGSEGV error.
I have confirmed this because I eventually wrapped the method with if (elt != NULL) and it still happened, so the problem must be something else.
Running out of clues, it occurred to me that this code, as it is, cannot be causing the error. It must be something obscure somewhere else in my code.
Let's see. If I perform an NSLog before the culprit line like this:
NSLog(#"[%# %#]" , [elt->target class],NSStringFromSelector(updateSelector));
I can tell what was the last scheduled object to be updated, and even get the corresponding method!
After making my testers crash again, I finally got this result:
[Game update]
Sweet. Game is the main game scene, so it seems like the problem is related to such scene.
But wait. There is no such method update for my scene. I never implemented something like that.
Then I figured that since Game is a CCScene object, maybe CCScene does have such method. But I see its implementation and it doesn't. But wait, CCScene is a subclass of CCNode! So let's take a look at CCNode.
... There are no update methods in CCNode either.
I did find something curious about CCNode:
-(void) scheduleUpdate;
Which apparently is in charge of scheduling the update method to be called once per frame - and it does. Here's a particular line of such procedure:
[target methodForSelector:updateSelector];
Where target is supposed to be Game and updateSelector is #selector(update:).
However, this doesn't make any sense: where is this update method supposed to be implemented? I do not find it anywhere in CCNode. Therefore, how could it possibly schedule such method?
Normally, I would say that this is what causes the error - that we're scheduling a method that is not implemented, thus causing a SIGSEGV error. However, this is plain weird, because if that was true, then it should be crashing all the time - but it doesn't.
And this is as far as I got trying to debug this error. What am I missing?
I know that you can't tell me where the problem is, but I believe that I got an important lead and you can shed some light on it: where is update implemented in cocos2d?
This is the full code of the tick method in CCScheduler, just in case:
-(void) tick: (ccTime) dt {
updateHashLocked = YES;
if( timeScale_ != 1.0f )
dt *= timeScale_;
// Iterate all over the Updates selectors
tListEntry *entry, *tmp;
// updates with priority < 0
DL_FOREACH_SAFE( updatesNeg, entry, tmp ) {
if( ! entry->paused && !entry->markedForDeletion )
entry->impMethod( entry->target, updateSelector, dt );
}
// updates with priority == 0
DL_FOREACH_SAFE( updates0, entry, tmp ) {
if( ! entry->paused && !entry->markedForDeletion )
{
entry->impMethod( entry->target, updateSelector, dt );
}
}
// updates with priority > 0
DL_FOREACH_SAFE( updatesPos, entry, tmp ) {
if( ! entry->paused && !entry->markedForDeletion )
entry->impMethod( entry->target, updateSelector, dt );
}
// Iterate all over the custome selectors
for(tHashSelectorEntry *elt=hashForSelectors; elt != NULL; ) {
currentTarget = elt;
currentTargetSalvaged = NO;
if( ! currentTarget->paused ) {
// The 'timers' ccArray may change while inside this loop.
for( elt->timerIndex = 0; elt->timerIndex < elt->timers->num; elt->timerIndex++) {
elt->currentTimer = elt->timers->arr[elt->timerIndex];
elt->currentTimerSalvaged = NO;
impMethod( elt->currentTimer, updateSelector, dt);
if( elt->currentTimerSalvaged ) {
// The currentTimer told the remove itself. To prevent the timer from
// accidentally deallocating itself before finishing its step, we retained
// it. Now that step is done, it's safe to release it.
[elt->currentTimer release];
}
elt->currentTimer = nil;
}
}
if (elt != NULL) {
// elt, at this moment, is still valid
// so it is safe to ask this here (issue #490)
elt = elt->hh.next;
// only delete currentTarget if no actions were scheduled during the cycle (issue #481)
if( currentTargetSalvaged && currentTarget->timers->num == 0 )
[self removeHashElement:currentTarget];
}
}
// delete all updates that are morked for deletion
// updates with priority < 0
DL_FOREACH_SAFE( updatesNeg, entry, tmp ) {
if(entry->markedForDeletion )
{
[self removeUpdateFromHash:entry];
}
}
// updates with priority == 0
DL_FOREACH_SAFE( updates0, entry, tmp ) {
if(entry->markedForDeletion )
{
[self removeUpdateFromHash:entry];
}
}
// updates with priority > 0
DL_FOREACH_SAFE( updatesPos, entry, tmp ) {
if(entry->markedForDeletion )
{
[self removeUpdateFromHash:entry];
}
}
updateHashLocked = NO;
currentTarget = nil;
}

Related

How to handle with return number given by lua_resume?

I have some coroutine handling code like this:
int coro_re_num = 0;
int coro_state = lua_resume( coro_lua, master_lua, narg, &coro_re_num);
if ( coro_state == LUA_OK)
{
// do something
}
else if ( coro_state == LUA_YIELD)
{
// do_something
}
else
{
const char* err = lua_tostring(coro_lua, -1);
log_error(err);
}
lua_pop(master_lua, coro_re_num);
When coroutine ends with OK or YIELD, it works properly. But when it ends with any error, the last lua_pop always fail, and I noticed the coro_re_num is relatively large (mostly more than 10) which causes stack underflow by lua_pop.
What does the coro_re_num means when the coroutine ends with error? How to handle it?

How to lock an array from audio processing for analysis

In my app I'm doing some audio processing.
In the for loop of the audio buffer, there is a NSMutable array. The loop is called a huge number of time every second (depending on the buffer size).
As an example :
#autoreleasepool
{
for ( int i = 0; i < tempBuffer.mDataByteSize / 2; ++i )
{
if ( samples[i] > trig)
{
[self.k_Array addObject:[NSNumber numberWithInt:k]];
// other stuff
}
}
}
Then, every second, I'm calling a function for other processing.
- (void)realtimeUpdate:(NSTimer*)theTimer
{
// Create a copy of the array
NSMutableArray *k_ArrayCopy = [NSMutableArray arrayWithArray:k_Array]; // CRASH with EXC_BAD_ACCESS code 1 error
//do some stuff with k_ArrayCopy
}
I sometime receive an EXC_BAD_ACCESS error because, I think, a locking problem of the array.
I spent a lot of time trying to get information on queues, locking, working copies, etc... but I'm lost on this specific case.
My questions :
do I have to use atomic or nonatomic for k_array ?
do I have to use a dispatch_sync function ? If so, where exactly ?
should the realtimeUpdate function be called on background ?
Thanks in advance !
Use dispatch queue that will solve problem
//create queue instance variable
dispatch_queue_t q = dispatch_queue_create("com.safearrayaccess.samplequeue", NULL);
//1.
#autoreleasepool
{
for ( int i = 0; i < tempBuffer.mDataByteSize / 2; ++i )
{
if ( samples[i] > trig)
{
dispatch_async(q, ^{
//queue block
[self.k_Array addObject:[NSNumber numberWithInt:k]];
});
// other stuff NOTE: if its operation on array do it in queue block only
}
}
}
//2.
- (void)realtimeUpdate:(NSTimer*)theTimer
{
// Create a copy of the array
__block NSMutableArray *k_ArrayCopy;//when you use any variable inside block add __block before it
dispatch_async(q, ^{
//queue block
k_ArrayCopy = [NSMutableArray arrayWithArray:k_Array];
});
//do some stuff with k_ArrayCopy
}
Now your add and read array operation are on same queue and it will not conflict..
For more details in using dispatch queue go through apples Grand Central Dispatch doc
Other way of doing this is use NSConditonLock

Lua crashing for no apparent reason

We have Lua integrated into a project but we've found an odd test case that crashes consistently on ARM:
data = {"A","B","C","D","E","F","G","H","I","J"};
function OnTick(_object)
local params = {};
return 1;
end
Here is the basics of how the function is being called from C++:
lua_getglobal(Lua, function_name->c_str()); // Push function name that we want to call onto the stack
if (lua_isnil(Lua, -1))
{
// Error
lua_pop(Lua, 1);
return -1;
}
lua_pushlightuserdata(Lua, (void*)object); // Push the reference object onto the stack
if (lua_pcall(Lua, 1, 1, 0) != 0)
{
// Error
lua_pop(Lua, 1);
return -1;
}
lua_pop(Lua, 1);
return 1;
OnTick crashes after being called around 5 times.
Lua appears to be crashing when the garbage collector tries to clean up. Anyone else come across something like this and solved it?
Resolved this issue, the client code was corrupting the Lua state

pthread_Join can't return after call pthread_cancel?

I used Eclispse Indigo + CDT 8.0.2 + cygwin to develope a multi-thread systerm, the code is below:
pthread_mutex_t mutexCmd = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t signalCmd = PTHREAD_COND_INITIALIZER;
void * Func(void * arg)
{
int iStatus;
while (1)
{
int a = 1;
pthread_cleanup_push(pthread_mutex_unlock, &mutexCmd);
pthread_mutex_lock(&mutexCmd);
iStatus = pthread_cond_wait(&signalCmd, &mutexCmd);
if (iStatus) {
err_abort(iStatus, "signalCmd status error");
}
if(arg->Cmd != navi_Go) //Just a command tag;
{
pthread_mutex_unlock(&(pNaviCtrl->mutexCmd));
continue;
}
//do some work
//.....
pthread_mutex_unlock(&mutexCmd);
pthread_cleanup_pop(1);
}
//pthread_detach(pthread_self());
return NULL;
}
int main()
{
int iStatus = 0;
pthread = tid;
iStatus = pthread_create(&tid;NULL, Func, NULL);
if(iStatus)
{
err_abort(iStatus, "Start pthread error");
}
// do some work
...
//Cancel thread
void * retval;
iStatus = pthread_cancel(tid)
iStatus = pthread_join(tid; &retval);
if(iStatus){
err_abort(iStatus,"Stop thread error");
}
return iStatus;
}
where program run, it stop at "iStatus = pthread_join(tid1; &retval);" couldn't go forward anymore, I think the thread could be happed to deadlock, but can't find the reason. I supposed after call pthread_cancel(), the thread will exit and return to the pthread_join(),
who can tell me what's wrong with my code?
Don't put cleanup_push and _pop inside the while loop. Don't call them more than once. If you look at them, they are macros that wrap the code between them in { }. They setup a longjump that is used when you call pthread_cancel.
pthread_cleanup_pop(1) tells the pthread library to not only pop the cleanup entry off the stack, but to also execute it. So that call will also implicitly call:
pthread_mutex_unlock(&mutexCmd);
Since you've already unlocked the mutex, that call has undefined behavior (assuming the mutex type is PTHREAD_MUTEX_NORMAL). I imagine that call is just never returning or something.
Note that your code has other problems handing the cleanup - if you execute the continue for the loop, you'll call pthread_cleanup_push() a second time (or more), which will add another cleanup context.
There may be other problems (I'm not very familiar with pthread_cancel()).

Bad file descriptor on pthread_detach

My pthread_detach calls fail with a "Bad file descriptor" error. The calls are in the destructor for my class and look like this -
if(pthread_detach(get_sensors) != 0)
printf("\ndetach on get_sensors failed with error %m", errno);
if(pthread_detach(get_real_velocity) != 0)
printf("\ndetach on get_real_velocity failed with error %m", errno);
I have only ever dealt with this error when using sockets. What could be causing this to happen in a pthread_detach call that I should look for? Or is it likely something in the thread callback that could be causing it? Just in case, the callbacks look like this -
void* Robot::get_real_velocity_thread(void* threadid) {
Robot* r = (Robot*)threadid;
r->get_real_velocity_thread_i();
}
inline void Robot::get_real_velocity_thread_i() {
while(1) {
usleep(14500);
sensor_packet temp = get_sensor_value(REQUESTED_VELOCITY);
real_velocity = temp.values[0];
if(temp.values[1] != -1)
real_velocity += temp.values[1];
} //end while
}
/*Callback for get sensors thread*/
void* Robot::get_sensors_thread(void* threadid) {
Robot* r = (Robot*)threadid;
r->get_sensors_thread_i();
} //END GETSENSORS_THREAD
inline void Robot::get_sensors_thread_i() {
while(1) {
usleep(14500);
if(sensorsstreaming) {
unsigned char receive;
int read = 0;
read = connection.PollComport(port, &receive, sizeof(unsigned char));
if((int)receive == 19) {
read = connection.PollComport(port, &receive, sizeof(unsigned char));
unsigned char rest[54];
read = connection.PollComport(port, rest, 54);
/* ***SET SENSOR VALUES*** */
//bump + wheel drop
sensor_values[0] = (int)rest[1];
sensor_values[1] = -1;
//wall
sensor_values[2] = (int)rest[2];
sensor_values[3] = -1;
...
...
lots more setting just like the two above
} //end if header == 19
} //end if sensors streaming
} //end while
} //END GET_SENSORS_THREAD_I
Thank you for any help.
The pthread_* functions return an error code; they do not set errno. (Well, they may of course, but not in any way that is documented.)
Your code should print the value returned by pthread_detach and print that.
Single Unix Spec documents two return values for this function: ESRCH (no thread by that ID was found) and EINVAL (the thread is not joinable).
Detaching threads in the destructor of an object seems silly. Firstly, if they are going to be detached eventually, why not just create them that way?
If there is any risk that the threads can use the object that is being destroyed, they need to be stopped, not detached. I.e. you somehow indicate to the threads that they should shut down, and then wait for them to reach some safe place after which they will not touch the object any more. pthread_join is useful for this.
Also, it is a little late to be doing that from the destructor. A destructor should only be run when the thread executing it is the only thread with a reference to that object. If threads are still using the object, then you're destroying it from under them.

Resources