[vlc-commits] qt: playlist: fix stack overflow

Romain Vimont git at videolan.org
Tue Nov 7 14:25:14 CET 2017


vlc | branch: master | Romain Vimont <rom at rom1v.com> | Tue Nov  7 09:53:46 2017 +0100| [991ed989345c28d5fced32a9a5e60f0e793fcab1] | committer: Hugo Beauzée-Luyssen

qt: playlist: fix stack overflow

The playlist tree may be arbitrary deep, so traversing it recursively
may lead to stack overflow.

Traverse it iteratively instead.

Fixes #18376

Signed-off-by: Hugo Beauzée-Luyssen <hugo at beauzee.fr>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=991ed989345c28d5fced32a9a5e60f0e793fcab1
---

 .../gui/qt/components/playlist/playlist_model.cpp  | 30 +++++++++++++++-------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/modules/gui/qt/components/playlist/playlist_model.cpp b/modules/gui/qt/components/playlist/playlist_model.cpp
index 2b6d0e1ccc..99e4c8f942 100644
--- a/modules/gui/qt/components/playlist/playlist_model.cpp
+++ b/modules/gui/qt/components/playlist/playlist_model.cpp
@@ -41,6 +41,7 @@
 #include <assert.h>
 #include <QFont>
 #include <QAction>
+#include <QStack>
 
 /*************************************************************************
  * Playlist model implementation
@@ -518,20 +519,31 @@ PLItem *PLModel::findByPLId( PLItem *root, int i_id ) const
     if( root->id() == i_id )
         return root;
 
-    QList<AbstractPLItem *>::iterator it = root->children.begin();
-    while ( it != root->children.end() )
+    /* traverse the tree (in depth first) iteratively to avoid stack overflow */
+
+    struct RemainingChildren {
+        QList<AbstractPLItem *>::const_iterator next;
+        QList<AbstractPLItem *>::const_iterator end;
+    };
+
+    QStack<RemainingChildren> stack;
+    if( root->childCount() )
+        stack.push( {root->children.cbegin(), root->children.cend()} );
+
+    while ( !stack.isEmpty() )
     {
-        PLItem *item = static_cast<PLItem *>(*it);
+        RemainingChildren &remainingChildren = stack.top();
+
+        PLItem *item = static_cast<PLItem *>( *remainingChildren.next );
         if( item->id() == i_id )
             return item;
 
+        if( ++remainingChildren.next == remainingChildren.end )
+            /* there are no more children at this depth level */
+            stack.pop();
+
         if( item->childCount() )
-        {
-            PLItem *childFound = findByPLId( item, i_id );
-            if( childFound )
-                return childFound;
-        }
-        ++it;
+            stack.push( {item->children.cbegin(), item->children.cend()} );
     }
     return NULL;
 }



More information about the vlc-commits mailing list