Merge pull request #6162 from dumganhar/pull/6160

Fixed a potential crash in EventDispatcher, based on PR #6160
This commit is contained in:
James Chen 2014-04-08 11:25:59 +08:00
commit c2b8557efb
3 changed files with 75 additions and 1 deletions

View File

@ -340,6 +340,27 @@ void EventDispatcher::removeEventListenersForTarget(Node* target, bool recursive
}
}
// Bug fix: ensure there are no references to the node in the list of listeners to be added.
// If we find any listeners associated with the destroyed node in this list then remove them.
// This is to catch the scenario where the node gets destroyed before it's listener
// is added into the event dispatcher fully. This could happen if a node registers a listener
// and gets destroyed while we are dispatching an event (touch etc.)
for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); )
{
EventListener * listener = *iter;
if (listener->getSceneGraphPriority() == target)
{
listener->setRegistered(false);
listener->release();
iter = _toAddedListeners.erase(iter);
}
else
{
++iter;
}
}
if (recursive)
{
const auto& children = target->getChildren();

View File

@ -8,6 +8,7 @@
#include "NewEventDispatcherTest.h"
#include "testResource.h"
#include "CCAutoreleasePool.h"
namespace {
@ -27,7 +28,8 @@ std::function<Layer*()> createFunctions[] =
CL(PauseResumeTargetTest),
CL(Issue4129),
CL(Issue4160),
CL(DanglingNodePointersTest)
CL(DanglingNodePointersTest),
CL(RegisterAndUnregisterWhileEventHanldingTest)
};
unsigned int TEST_CASE_COUNT = sizeof(createFunctions) / sizeof(createFunctions[0]);
@ -1413,3 +1415,44 @@ std::string DanglingNodePointersTest::subtitle() const
"CC_NODE_DEBUG_VERIFY_EVENT_LISTENERS == 1\n&& COCOS2D_DEBUG > 0";
#endif
}
RegisterAndUnregisterWhileEventHanldingTest::RegisterAndUnregisterWhileEventHanldingTest()
{
Point origin = Director::getInstance()->getVisibleOrigin();
Size size = Director::getInstance()->getVisibleSize();
auto callback1 = [=](DanglingNodePointersTestSprite * sprite)
{
auto callback2 = [](DanglingNodePointersTestSprite * sprite)
{
CCASSERT(false, "This should never get called!");
};
{
AutoreleasePool pool;
auto sprite2 = DanglingNodePointersTestSprite::create(callback2);
sprite2->setTexture("Images/CyanSquare.png");
sprite2->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite2, 0);
removeChild(sprite2);
}
};
auto sprite1 = DanglingNodePointersTestSprite::create(callback1);
sprite1->setTexture("Images/CyanSquare.png");
sprite1->setPosition(origin+Point(size.width/2, size.height/2));
addChild(sprite1, -10);
}
std::string RegisterAndUnregisterWhileEventHanldingTest::title() const
{
return "RegisterAndUnregisterWhileEventHanldingTest";
}
std::string RegisterAndUnregisterWhileEventHanldingTest::subtitle() const
{
return "Tap the square multiple times - should not crash!";
}

View File

@ -217,4 +217,14 @@ public:
virtual std::string subtitle() const override;
};
class RegisterAndUnregisterWhileEventHanldingTest : public EventDispatcherTestDemo
{
public:
CREATE_FUNC(RegisterAndUnregisterWhileEventHanldingTest);
RegisterAndUnregisterWhileEventHanldingTest();
virtual std::string title() const override;
virtual std::string subtitle() const override;
};
#endif /* defined(__samples__NewEventDispatcherTest__) */