summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Vasenev <alexey.vasenev@gameless.one>2024-07-29 20:20:55 +0300
committerPedro J. Estébanez <pedrojrulez@gmail.com>2024-09-05 13:28:58 +0200
commit257dd2f9e51b4f770f230d0766f74880a7c8d383 (patch)
tree076ff469e21d90e148c0507b94b561b748983e18
parent1c4849b162151df3f36b0e24d6f9cf70ccbce8ea (diff)
downloadredot-engine-257dd2f9e51b4f770f230d0766f74880a7c8d383.tar.gz
Fix use condition_variable after free
(cherry picked from commit 2ff6594928f0d6004ca76359af8e31c504b0bd57)
-rw-r--r--core/io/resource_loader.cpp20
-rw-r--r--core/io/resource_loader.h2
2 files changed, 14 insertions, 8 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 3a61653c95..3345b92108 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -336,11 +336,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
load_task.status = THREAD_LOAD_LOADED;
}
- if (load_task.cond_var) {
+ if (load_task.cond_var && load_task.need_wait) {
load_task.cond_var->notify_all();
- memdelete(load_task.cond_var);
- load_task.cond_var = nullptr;
}
+ load_task.need_wait = false;
bool ignoring = load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP;
bool replacing = load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE || load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP;
@@ -729,15 +728,21 @@ Ref<Resource> ResourceLoader::_load_complete_inner(LoadToken &p_load_token, Erro
DEV_ASSERT(wtp_task_err == OK);
thread_load_mutex.lock();
}
- } else {
+ } else if (load_task.need_wait) {
// Loading thread is main or user thread.
if (!load_task.cond_var) {
load_task.cond_var = memnew(ConditionVariable);
}
+ load_task.awaiters_count++;
do {
load_task.cond_var->wait(p_thread_load_lock);
DEV_ASSERT(thread_load_tasks.has(p_load_token.local_path) && p_load_token.get_reference_count());
- } while (load_task.cond_var);
+ } while (load_task.need_wait);
+ load_task.awaiters_count--;
+ if (load_task.awaiters_count == 0) {
+ memdelete(load_task.cond_var);
+ load_task.cond_var = nullptr;
+ }
}
} else {
if (loader_is_wtp) {
@@ -1165,11 +1170,10 @@ void ResourceLoader::clear_thread_load_tasks() {
if (thread_load_tasks.size()) {
for (KeyValue<String, ResourceLoader::ThreadLoadTask> &E : thread_load_tasks) {
if (E.value.status == THREAD_LOAD_IN_PROGRESS) {
- if (E.value.cond_var) {
+ if (E.value.cond_var && E.value.need_wait) {
E.value.cond_var->notify_all();
- memdelete(E.value.cond_var);
- E.value.cond_var = nullptr;
}
+ E.value.need_wait = false;
none_running = false;
}
}
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 9d07964105..ec9997891e 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -167,6 +167,8 @@ private:
Thread::ID thread_id = 0; // Used if running on an user thread (e.g., simple non-threaded load).
bool awaited = false; // If it's in the pool, this helps not awaiting from more than one dependent thread.
ConditionVariable *cond_var = nullptr; // In not in the worker pool or already awaiting, this is used as a secondary awaiting mechanism.
+ uint32_t awaiters_count = 0;
+ bool need_wait = true;
LoadToken *load_token = nullptr;
String local_path;
String remapped_path;