Fix a crash of the TextureManager 05/230905/1
authorHeeyong Song <heeyong.song@samsung.com>
Tue, 14 Apr 2020 05:30:18 +0000 (14:30 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Thu, 16 Apr 2020 03:45:51 +0000 (12:45 +0900)
The observer may be deleted during the UploadComplete callback.
So disconnect the signal and erase the object from the list first.

Change-Id: I614008c9a93025aef973dc8fcf38e1b578f8f35c

automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
dali-toolkit/internal/visuals/texture-manager-impl.cpp

index bd15bb0..5255f10 100755 (executable)
@@ -74,6 +74,7 @@ static void TestKeyInputFocusCallback( Control control )
 
 const char* TEST_LARGE_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/tbcol.png";
 const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/Kid1.svg";
 
 Vector4 GetControlBackgroundColor( Control& control )
 {
@@ -87,6 +88,20 @@ Vector4 GetControlBackgroundColor( Control& control )
   return color;
 }
 
+bool gResourceReadySignalFired = false;
+
+void ResourceReadySignal( Control control )
+{
+  if( control.GetVisualResourceStatus( Control::Property::BACKGROUND ) == Visual::ResourceStatus::FAILED )
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert( ImageVisual::Property::URL, TEST_SVG_FILE_NAME );
+    control.SetProperty( Control::Property::BACKGROUND, propertyMap );
+  }
+
+  gResourceReadySignalFired = true;
+}
+
 } // namespace
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -986,6 +1001,38 @@ int UtcDaliControlResourcesReady(void)
   END_TEST;
 }
 
+int UtcDaliControlResourcesReady02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Change a resource during ResourceReady callback" );
+
+  gResourceReadySignalFired = false;
+
+  Control control = Control::New();
+  control.SetSize( 200.f, 200.f );
+  control.ResourceReadySignal().Connect( &ResourceReadySignal );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( ImageVisual::Property::URL, "invalid.jpg" );
+  control.SetProperty( Control::Property::BACKGROUND, propertyMap );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( control.IsResourceReady(), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+  gResourceReadySignalFired = false;
+
+  END_TEST;
+}
+
 int UtcDaliControlMarginProperty(void)
 {
   ToolkitTestApplication application;
index b34b9f1..71385e2 100644 (file)
@@ -1016,6 +1016,12 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
     DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "NotifyObservers() url:%s loadState:%s\n",
                    textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState ) );
 
+    // It is possible for the observer to be deleted.
+    // Disconnect and remove the observer first.
+    observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
+
+    info->observerList.Erase( info->observerList.begin() );
+
     if( info->loadPixelBuffer )
     {
       observer->LoadComplete( success, info->pixelBuffer, info->url, info->preMultiplied );
@@ -1026,8 +1032,6 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
                                 info->preMultiplied );
     }
 
-    observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
-
     // Get the textureInfo from the container again as it may have been invalidated.
     int textureInfoIndex = GetCacheIndexFromId( textureId );
     if( textureInfoIndex == INVALID_CACHE_INDEX)
@@ -1035,16 +1039,6 @@ void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
       break; // texture has been removed - can stop.
     }
     info = &mTextureInfoContainer[ textureInfoIndex ];
-
-    // remove the observer that was just triggered if it's still in the list
-    for( TextureInfo::ObserverListType::Iterator j = info->observerList.Begin(); j != info->observerList.End(); ++j )
-    {
-      if( *j == observer )
-      {
-        info->observerList.Erase( j );
-        break;
-      }
-    }
   }
 
   mQueueLoadFlag = false;