Skip to content

[Bug] <title>Crash when addressing a renamed parent folder from inside its nested structure (StackOverflowError) #6439

@lionKLn

Description

@lionKLn

Describe the bug

The app crashes with a StackOverflowError when attempting to delete a folder that has been renamed, while navigating deep within its nested child structure.

This seems to be caused by uncontrolled recursion in RealSavedSitesRepository.traverseBranch(), likely due to cyclic or deep traversal of a folder structure.

stack trace:
FATAL EXCEPTION: DefaultDispatcher-worker-10
Process: com.duckduckgo.mobile.android.debug, PID: 31900
java.lang.StackOverflowError: stack size 1035KB
at java.lang.Object.hashCode(Object.java:122)
at java.util.WeakHashMap.hash(WeakHashMap.java:303)
at java.util.WeakHashMap.put(WeakHashMap.java:455)
at android.database.sqlite.SQLiteConnectionPool.finishAcquireConnectionLocked(SQLiteConnectionPool.java:1026)
at android.database.sqlite.SQLiteConnectionPool.tryAcquirePrimaryConnectionLocked(SQLiteConnectionPool.java:960)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:723)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:392)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:896)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:62)
at android.database.sqlite.SQLiteQuery.(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1714)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1689)
at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.query(FrameworkSQLiteDatabase.kt:156)
at androidx.room.RoomDatabase.query(RoomDatabase.kt:484)
at androidx.room.util.DBUtil.query(DBUtil.kt:75)
at com.duckduckgo.savedsites.store.SavedSitesRelationsDao_Impl.countEntitiesInFolder(SavedSitesRelationsDao_Impl.kt:589)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.mapToBookmarkFolder(SavedSitesRepository.kt:597)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.folderContent(SavedSitesRepository.kt:201)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.traverseBranch(SavedSitesRepository.kt:181)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.traverseBranch(SavedSitesRepository.kt:185)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.traverseBranch(SavedSitesRepository.kt:185)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.traverseBranch(SavedSitesRepository.kt:185)

………(repeat)

at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.traverseBranch(SavedSitesRepository.kt:185)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.getFolderBranch(SavedSitesRepository.kt:172)
at com.duckduckgo.savedsites.impl.RealSavedSitesRepository.deleteFolderBranch(SavedSitesRepository.kt:210)
at com.duckduckgo.savedsites.impl.bookmarks.BookmarksViewModel$delete$2.invokeSuspend(BookmarksViewModel.kt:328)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:811)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:715)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:702)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelled}@4253af9, [Dispatchers.IO](http://dispatchers.io/)]

How to Reproduce

  1. Open the  DuckDuckGo app
  2. Navigate to Bookmarks
  3. Add a new folder named "a"
  4. Enter folder "a"
  5. Add a subfolder named "b" inside "a"
  6. Enter folder "b"
  7. Use the search bar to find folder "a" again
  8. Click the Edit option for folder "a", and rename it to "c"
  9. After renaming, delete folder "c"
  10. App crashes
output_silent.webm

Expected behavior

The folder should be safely deleted without causing the app to crash.

Environment

- DDG App Version:5.238.0
- Device:Pixel 5
- OS:Android 14

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions