Repository: godot
Issue: `Vector`'s constructor fails to create a reference to the other `Vector` when the other thread writes to that object
Labels: bug,topic:core,confirmed,needs testing

### Tested versions

Reproducible in: v3.0 [362774c6176596f87506e3d330dd1d12b0b75e19], master [475248d99df89fc29032a42f1d29ad4cef49c8b5]

### System information

Ubuntu 22.04.4 LTS 22.04

### Issue description

* Causes: #86428. Decided to create another issue as this issue is broader. Can be transformed into a tracker of similar issues.

`Vector`'s constructor fails to create a reference to the other `Vector` when the other thread writes to that object. Not sure if it's intentional and `Vector` is just not meant to be thread-safe.

### Steps to reproduce

Store an `Vector` object. Write to it from one thread and read from the other at the same time.

### Minimal reproduction project (MRP)

<details><summary>3.0 (run with godot --test thread)</summary>

```diff
diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp
index 3d5ca70c439..3dd292d9362 100644
--- a/main/tests/test_main.cpp
+++ b/main/tests/test_main.cpp
@@ -45,6 +45,7 @@
 #include "test_render.h"
 #include "test_shader_lang.h"
 #include "test_string.h"
+#include "test_thread.h"
 
 const char **tests_get_names() {
 
@@ -72,6 +73,11 @@ const char **tests_get_names() {
 
 MainLoop *test_main(String p_test, const List<String> &p_args) {
 
+	if (p_test == "thread") {
+
+		return TestThread::test();
+	}
+
 	if (p_test == "string") {
 
 		return TestString::test();
diff --git a/main/tests/test_thread.cpp b/main/tests/test_thread.cpp
new file mode 100644
index 00000000000..c19d066dd81
--- /dev/null
+++ b/main/tests/test_thread.cpp
@@ -0,0 +1,43 @@
+#include "test_thread.h"
+
+#include "core/os/os.h"
+#include "core/os/thread.h"
+
+#include <atomic>
+
+namespace TestThread {
+
+std::atomic<bool> test_exit;
+Vector<int32_t> test_vec;
+
+void test_func(void*) {
+	print_line("Running thread");
+	while (!test_exit) {
+		for (int i = 0; i < test_vec.size(); i++) {
+			test_vec[i] = 0;
+		}
+		OS::get_singleton()->delay_usec(1000);
+	}
+}
+
+MainLoop *test() {
+	test_exit.store(false);
+	test_vec.resize(1000);
+
+	Thread* thread = Thread::create(test_func, nullptr);
+
+	for (int i = 0; i < 1000000; i++) {
+		Vector<int32_t> val = test_vec;
+		if (val.ptr() == nullptr) {
+			print_line("test_vec has nullptr pointer");
+			break;
+		}
+
+		OS::get_singleton()->delay_usec(1000);
+	}
+
+	test_exit.store(true);
+	Thread::wait_to_finish(thread);
+	return nullptr;
+}
+} // namespace TestThread
diff --git a/main/tests/test_thread.h b/main/tests/test_thread.h
new file mode 100644
index 00000000000..58d53c82e06
--- /dev/null
+++ b/main/tests/test_thread.h
@@ -0,0 +1,11 @@
+#ifndef TEST_THREAD_H
+#define TEST_THREAD_H
+
+#include "os/main_loop.h"
+
+namespace TestThread {
+
+MainLoop *test();
+}
+
+#endif

```
</details> 
<details><summary>master (run with godot --test --test-case="*[Thread]*")</summary>

```diff
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 3c875797a49..2b7a60f6fa5 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -126,6 +126,7 @@
 #include "tests/scene/test_window.h"
 #include "tests/servers/rendering/test_shader_preprocessor.h"
 #include "tests/servers/test_text_server.h"
+#include "tests/test_thread.h"
 #include "tests/test_validate_testing.h"
 
 #ifndef _3D_DISABLED
diff --git a/tests/test_thread.h b/tests/test_thread.h
new file mode 100644
index 00000000000..f25a61ddc67
--- /dev/null
+++ b/tests/test_thread.h
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/*  test_thread.h                                                         */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef TEST_THREAD_H
+#define TEST_THREAD_H
+
+#include "tests/test_macros.h"
+
+#include "core/os/os.h"
+#include "core/os/thread.h"
+
+namespace TestThread {
+
+std::atomic<bool> test_exit;
+Vector<int32_t> test_vec;
+
+void test_func(void *) {
+	print_line("Running thread");
+	while (!test_exit) {
+		for (int i = 0; i < test_vec.size(); i++) {
+			test_vec.write[i] = 0;
+		}
+		OS::get_singleton()->delay_usec(1000);
+	}
+}
+
+TEST_CASE("[Thread] Example test case") {
+	test_exit.store(false);
+	test_vec.resize(1000);
+
+	Thread thread;
+	thread.start(test_func, nullptr);
+
+	for (int i = 0; i < 1000000; i++) {
+		Vector<int32_t> val = test_vec;
+		WARN(val.ptr() != nullptr);
+
+		OS::get_singleton()->delay_usec(1000);
+	}
+
+	test_exit.store(true);
+	thread.wait_to_finish();
+}
+
+} // namespace TestThread
+
+#endif // TEST_THREAD_H

```
</details> 
<details><summary>master with CowData (run with godot --test --test-case="*[Thread]*")</summary>

```diff
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 3c875797a49..2b7a60f6fa5 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -126,6 +126,7 @@
 #include "tests/scene/test_window.h"
 #include "tests/servers/rendering/test_shader_preprocessor.h"
 #include "tests/servers/test_text_server.h"
+#include "tests/test_thread.h"
 #include "tests/test_validate_testing.h"
 
 #ifndef _3D_DISABLED
diff --git a/tests/test_thread.h b/tests/test_thread.h
new file mode 100644
index 00000000000..7f5800caa6b
--- /dev/null
+++ b/tests/test_thread.h
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/*  test_thread.h                                                         */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#ifndef TEST_THREAD_H
+#define TEST_THREAD_H
+
+#include "tests/test_macros.h"
+
+#include "core/os/os.h"
+#include "core/os/thread.h"
+
+namespace TestThread {
+
+std::atomic<bool> test_exit;
+CowData<int32_t> test_vec;
+
+void test_func(void *) {
+	print_line("Running thread");
+	while (!test_exit) {
+		for (int i = 0; i < test_vec.size(); i++) {
+			test_vec.ptrw()[i] = 0;
+		}
+		OS::get_singleton()->delay_usec(1000);
+	}
+}
+
+TEST_CASE("[Thread] Example test case") {
+	test_exit.store(false);
+	test_vec.resize(1000);
+
+	Thread thread;
+	thread.start(test_func, nullptr);
+
+	for (int i = 0; i < 1000000; i++) {
+		CowData<int32_t> val = test_vec;
+		WARN(val.ptr() != nullptr);
+
+		OS::get_singleton()->delay_usec(1000);
+	}
+
+	test_exit.store(true);
+	thread.wait_to_finish();
+}
+
+} // namespace TestThread
+
+#endif // TEST_THREAD_H

```
</details>