Bug/Crash: While handleing a notification and register/add new observers to the CCNotificationCenter observer array


#1

Hi developer,

I found a bug/crash which appears in the CCNotificationCenter::postNotification.
When CCNotificationCenter::postNotification was called and inside the call some new notification observers were added, an invalid object will be accessed (7 of 10 cases).
The bug/crash only appears if the array m_observers of CCNotificationCenter gets resized.

I locate the error in the CCARRAY_FOREACH, CCARRAY_FOREACH_REVERSE macros and the ccArrayDoubleCapacity function.

@ void ccArrayDoubleCapacity(ccArray **arr) @
@ { @
@ arr~~>max = 2; @
@ CCObject
* newArr = realloc ); // Hint: The function may move the memory block to a new location, in which case the new location is returned. @
@ // will fail when there’s not enough memory @
@ CCAssert; @
@ arr~~>arr = newArr; @
@ } @
@ #define CCARRAY_FOREACH @
@ if && >data>num > 0) @
@ for~~>data~~>arr,***end = >data>arr + >data>num-1; @
@ arr <= end && =arr) != NULL/* || true*/); @
@ arr
) @
@ #define CCARRAY_FOREACH_REVERSE @
@ if && >data>num > 0) @
@ for~~>data~~>arr
>data>num-1, ****end = >data>arr; @
@ arr >= end && =arr) != NULL/ || true*/); @
@ arr—) @

ccArrayDoubleCapacity uses realloc to increase the size of the array. Realloc may move the memory block to a new position if the memory block could not increased at the old position. The macros uses pointers to iterate over the objects in the array. And here is the problem, if realloc couldn’t keep the memory block at the same adress the macro uses the old and now invalid pointers.
My suggestion would, instead of using pointers in the macros, work with the array indices.
@ #define CCARRAY_FOREACH @
@ if && >data>num > 0) @
@ for~~>data~~>num; @
@ macroIndex < end && = >data>arr[macroIndex]) != NULL/* || true*/); @
@*+macroIndex) @

@ #define CCARRAY_FOREACH_REVERSE(array, object) @
@ if ((array) && (array)>data>num > 0) @
@ for(unsigned int macroIndex = (array)>data>num - 1; @
@ macroIndex < (array)>data>num && (((object) = (array)>data>arr[macroIndex]) != NULL/* || true*/); @
@ —macroIndex) @

Best regards,

Ingo Heßling