From ca46a90db82897ed2292be3c1bbda36baa6c4603 Mon Sep 17 00:00:00 2001 From: Nguyen Van Nam Date: Mon, 30 Mar 2026 00:42:55 +0700 Subject: [PATCH] refactor: bitmap cache uses non-thread-safe hashmap from potentially concurrent callers `cachedBitmaps` is a global mutable `HashMap` accessed without synchronization in `getImageBitmapFromUrl`. This utility is likely called from multiple coroutine/background contexts. Concurrent read/write on `HashMap` is unsafe and can lead to race conditions, stale reads, or map corruption/crashes under load. Affected files: DownloadUtils.kt Signed-off-by: Nguyen Van Nam --- .../cloudstream3/utils/downloader/DownloadUtils.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadUtils.kt index b436bb49c8e..9f2c31d9a37 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadUtils.kt @@ -20,16 +20,17 @@ import com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getFol import com.lagradost.cloudstream3.utils.txt import kotlinx.coroutines.Job import kotlinx.coroutines.runBlocking +import java.util.concurrent.ConcurrentHashMap /** Separate object with helper functions for the downloader */ object DownloadUtils { - private val cachedBitmaps = hashMapOf() + private val cachedBitmaps = ConcurrentHashMap() internal fun Context.getImageBitmapFromUrl( url: String, headers: Map? = null ): Bitmap? = safe { - if (cachedBitmaps.containsKey(url)) { - return@safe cachedBitmaps[url] + cachedBitmaps[url]?.let { + return@safe it } val imageLoader = SingletonImageLoader.get(this) @@ -50,7 +51,7 @@ object DownloadUtils { } bitmap?.let { - cachedBitmaps[url] = it + cachedBitmaps.putIfAbsent(url, it) } return@safe bitmap