Procházet zdrojové kódy

Preventing the addition or deletion of new forms from within Form::mouseEventInternal, Form::touchEventInternal or Form::keyEventInternal from causing a crash.
Preventing the cleanup of forms from within a Control::Listener event from causing a crash.
Adding Control::_alignment to the initialization list.

Adam Blake před 13 roky
rodič
revize
eaa23b0e7d

+ 16 - 0
gameplay/src/Container.cpp

@@ -581,6 +581,11 @@ bool Container::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 
 bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
 {
+    // This event may run untrusted code by notifying listeners of events.
+    // If the user calls exit() or otherwise releases this container, we
+    // need to keep it alive until the method returns.
+    addRef();
+
     std::vector<Control*>::const_iterator it;
     for (it = _controls.begin(); it < _controls.end(); it++)
     {
@@ -595,6 +600,7 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
         {
             if (control->keyEvent(evt, key))
             {
+                release();
                 return _consumeInputEvents;
             }
             else if (evt == Keyboard::KEY_CHAR && key == Keyboard::KEY_TAB)
@@ -614,6 +620,7 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
                     if (nextControl->getFocusIndex() == focusIndex)
                     {
                         nextControl->setState(Control::FOCUS);
+                        release();
                         return _consumeInputEvents;
                     }
                 }
@@ -621,6 +628,7 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
         }
     }
 
+    release();
     return false;
 }
 
@@ -1005,6 +1013,11 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         return false;
     }
 
+    // This event may run untrusted code by notifying listeners of events.
+    // If the user calls exit() or otherwise releases this container, we
+    // need to keep it alive until the method returns.
+    addRef();
+
     bool eventConsumed = false;
     const Theme::Border& border = getBorder(_state);
     const Theme::Padding& padding = getPadding();
@@ -1058,6 +1071,7 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
 
     if (!isEnabled())
     {
+        release();
         return (_consumeInputEvents | eventConsumed);
     }
     
@@ -1077,6 +1091,7 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         {
             setState(Control::NORMAL);
             _contactIndex = INVALID_CONTACT_INDEX;
+            release();
             return false;
         }
         break;
@@ -1100,6 +1115,7 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         }
     }
 
+    release();
     return (_consumeInputEvents | eventConsumed);
 }
 

+ 8 - 1
gameplay/src/Control.cpp

@@ -7,7 +7,7 @@ namespace gameplay
 
 Control::Control()
     : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
-    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _autoWidth(false), _autoHeight(false), _listeners(NULL),
+    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT), _autoWidth(false), _autoHeight(false), _listeners(NULL),
     _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(0), _parent(NULL), _styleOverridden(false), _skin(NULL)
 {
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
@@ -798,6 +798,11 @@ bool Control::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 
 void Control::notifyListeners(Listener::EventType eventType)
 {
+    // This method runs untrusted code by notifying listeners of events.
+    // If the user calls exit() or otherwise releases this control, we
+    // need to keep it alive until the method returns.
+    addRef();
+
     if (_listeners)
     {
         std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
@@ -813,6 +818,8 @@ void Control::notifyListeners(Listener::EventType eventType)
     }
 
     fireScriptEvent<void>("controlEvent", this, eventType);
+
+    release();
 }
 
 void Control::update(const Control* container, const Vector2& offset)

+ 2 - 0
gameplay/src/Control.h

@@ -15,6 +15,8 @@
 namespace gameplay
 {
 
+class Container;
+
 /**
  * Base class for UI controls.
  */

+ 9 - 9
gameplay/src/Form.cpp

@@ -592,10 +592,10 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
     // Check for a collision with each Form in __forms.
     // Pass the event on.
     bool eventConsumed = false;
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    size_t size = __forms.size();
+    for (size_t i = 0; i < size; ++i)
     {
-        Form* form = *it;
+        Form* form = __forms[i];
         GP_ASSERT(form);
 
         if (form->isEnabled())
@@ -639,10 +639,10 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
 
 bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    size_t size = __forms.size();
+    for (size_t i = 0; i < size; ++i)
     {
-        Form* form = *it;
+        Form* form = __forms[i];
         GP_ASSERT(form);
         if (form->isEnabled())
         {
@@ -657,10 +657,10 @@ bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
 {
     bool eventConsumed = false;
 
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    size_t size = __forms.size();
+    for (size_t i = 0; i < size; ++i)
     {
-        Form* form = *it;
+        Form* form = __forms[i];
         GP_ASSERT(form);
 
         if (form->isEnabled())