[NUI] Resolve DisposeRecursively crashed when we dispose scrollbase
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 27 Oct 2023 09:47:55 +0000 (18:47 +0900)
committerTaehyub Kim <taehyub.kim@samsung.com>
Mon, 30 Oct 2023 12:38:47 +0000 (21:38 +0900)
Due to some app's implements, ContentView can be disposed before ScrollBase
itself disposed. In this case, ContentView is not null.

So, when we try to call RemovePropertyNotification, it become crashed.

To avoid these cases, let we make DisposeRecursively API makes more safety.

And also, fix some crash issue in PerformanceTest1Page.xaml.cs what
can be problem in future.

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
src/Tizen.NUI.Components/Controls/ScrollableBase.cs
src/Tizen.NUI/src/public/Common/Container.cs
test/NUITizenGallery/Examples/PerformanceTest/PerformanceTest1Page.xaml.cs

index 6ecd82d842f3aa60a7202b2af14e21a6789e366b..b2cecd8ef1a3b3c2014f4bd33514ec130ebfe11c 100755 (executable)
@@ -1388,7 +1388,10 @@ namespace Tizen.NUI.Components
                 mPanGestureDetector?.Dispose();
                 mPanGestureDetector = null;
 
-                ContentContainer?.RemovePropertyNotification(propertyNotification);
+                if(!(ContentContainer?.Disposed ?? true) && propertyNotification != null)
+                {
+                    ContentContainer?.RemovePropertyNotification(propertyNotification);
+                }
                 propertyNotification?.Dispose();
                 propertyNotification = null;
             }
index fdfbf2c9c814ad2c3a667c33b355558cdebcd49a..9c85ac4616a7ec15a466385b6ac3c8ccb4a72f75 100755 (executable)
@@ -18,6 +18,7 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Linq;
 using Tizen.NUI.BaseComponents;
 using Tizen.NUI.Binding;
 using Tizen.NUI.Binding.Internals;
@@ -249,18 +250,24 @@ namespace Tizen.NUI
         public void DisposeRecursively()
         {
             // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
-            if(!Disposed && !IsDisposeQueued)
+            if (!Disposed && !IsDisposeQueued)
             {
                 Dispose();
             }
 
-            foreach (View child in Children)
-            {
-                child.DisposeRecursively();
-            }
+            // Copy child referecen to avoid Children changed during DisposeRecursively();
+            var copiedChildren = childViews.ToList();
 
             // Make sure that itself don't have children anymore.
             childViews?.Clear();
+
+            foreach (View child in copiedChildren)
+            {
+                if (!(child?.Disposed ?? true))
+                {
+                    child.DisposeRecursively();
+                }
+            }
         }
 
         /// <summary>
index 260077782cf3a33fca2140ad1712df599bc6b036..4fb0efd3cff99d58dda8a75f2715d97e3cfe807a 100644 (file)
@@ -98,8 +98,6 @@ namespace NUITizenGallery
 
         protected override void Dispose(DisposeTypes type)
         {
-            AppWindow.RemoveFrameUpdateCallback(FPSCounter);
-
             if (Disposed)
             {
                 return;
@@ -107,6 +105,7 @@ namespace NUITizenGallery
 
             if (type == DisposeTypes.Explicit)
             {
+                AppWindow.RemoveFrameUpdateCallback(FPSCounter);
                 RemoveAllChildren(true);
             }