godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.06k stars 21.18k forks source link

Usage of freed memory in OpenSimplexNoise::get_noise_4d #37032

Closed qarmin closed 4 years ago

qarmin commented 4 years ago

Godot version: 4.0.dev.custom_build. f65781fe7

OS/device including version: Ubuntu 19.10

Issue description: Backtrace:

[1] /lib/x86_64-linux-gnu/libc.so.6(+0x46470) [0x7f49fbd97470] (??:0)
[2] godot() [0x1c4e1b0] (/mnt/KubuntuWolne/godot/thirdparty/misc/open-simplex-noise.c:124)
[3] godot(open_simplex_noise4+0xea5) [0x1c527d3] (/mnt/KubuntuWolne/godot/thirdparty/misc/open-simplex-noise.c:1145)
[4] OpenSimplexNoise::_get_octave_noise_4d(int, float, float, float, float) (/mnt/KubuntuWolne/godot/modules/opensimplex/open_simplex_noise.h:88)
[5] OpenSimplexNoise::get_noise_4d(float, float, float, float) (/mnt/KubuntuWolne/godot/modules/opensimplex/open_simplex_noise.cpp:262)
[6] OpenSimplexNoise::get_seamless_image(int) (/mnt/KubuntuWolne/godot/modules/opensimplex/open_simplex_noise.cpp:144)
[7] NoiseTexture::_generate_texture() (/mnt/KubuntuWolne/godot/modules/opensimplex/noise_texture.cpp:145 (discriminator 1))
[8] NoiseTexture::_thread_function(void*) (/mnt/KubuntuWolne/godot/modules/opensimplex/noise_texture.cpp:126 (discriminator 2))
[9] ThreadPosix::thread_callback(void*) (/mnt/KubuntuWolne/godot/drivers/unix/thread_posix.cpp:76)
[10] /lib/x86_64-linux-gnu/libpthread.so.0(+0x9669) [0x7f49fc2aa669] (??:0)
[11] /lib/x86_64-linux-gnu/libc.so.6(clone+0x43) [0x7f49fbe73323] (??:0)

Address Sanitizer Log

modules/opensimplex/open_simplex_noise.cpp:255:15: runtime error: member access within address 0x625004058910 which does not point to an object of type 'OpenSimplexNoise'
0x625004058910: note: object is of type 'Object'
 be be be be  a8 82 28 18 00 00 00 00  00 00 00 00 00 00 00 00  00 be be be 00 00 00 00  00 00 00 00
              ^~~~~~~~~~~~~~~~~~~~~~~
              vptr for 'Object'
=================================================================
==10407==ERROR: AddressSanitizer: heap-use-after-free on address 0x62500405aea8 at pc 0x0000030f9c3f bp 0x7f00efb8b8b0 sp 0x7f00efb8b8a0
READ of size 4 at 0x62500405aea8 thread T79
    #0 0x30f9c3e in OpenSimplexNoise::get_noise_4d(float, float, float, float) modules/opensimplex/open_simplex_noise.cpp:255
    #1 0x30f39f0 in OpenSimplexNoise::get_seamless_image(int) modules/opensimplex/open_simplex_noise.cpp:144
    #2 0x30ce9e0 in NoiseTexture::_generate_texture() modules/opensimplex/noise_texture.cpp:145
    #3 0x30cd6be in NoiseTexture::_thread_function(void*) modules/opensimplex/noise_texture.cpp:126
    #4 0x61a5aad in ThreadPosix::thread_callback(void*) drivers/unix/thread_posix.cpp:74
    #5 0x7f0108f73668 in start_thread /build/glibc-t7JzpG/glibc-2.30/nptl/pthread_create.c:479
    #6 0x7f01081d4322 in clone (/lib/x86_64-linux-gnu/libc.so.6+0x122322)

0x62500405aea8 is located 9640 bytes inside of 9656-byte region [0x625004058900,0x62500405aeb8)
freed by thread T0 here:
    #0 0x7f010935f6ef in __interceptor_free (/lib/x86_64-linux-gnu/libasan.so.5+0x10d6ef)
    #1 0x1003daf7 in Memory::free_static(void*, bool) core/os/memory.cpp:178
    #2 0x30dfa10 in void memdelete<OpenSimplexNoise>(OpenSimplexNoise*) core/os/memory.h:119
    #3 0x30dc05f in Ref<OpenSimplexNoise>::unref() core/reference.h:246
    #4 0x30dc1a2 in Ref<OpenSimplexNoise>::ref(Ref<OpenSimplexNoise> const&) core/reference.h:68
    #5 0x30db589 in Ref<OpenSimplexNoise>::operator=(Ref<OpenSimplexNoise> const&) core/reference.h:141
    #6 0x30d069f in NoiseTexture::set_noise(Ref<OpenSimplexNoise>) modules/opensimplex/noise_texture.cpp:188
    #7 0x30eced1 in MethodBind1<Ref<OpenSimplexNoise> >::call(Object*, Variant const**, int, Callable::CallError&) core/method_bind.gen.inc:775
    #8 0xfaafd20 in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:903
    #9 0xfd1ebd0 in Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Callable::CallError&) core/variant_call.cpp:1222
    #10 0x42cdf1d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_function.cpp:1102
    #11 0x41332af in GDScriptInstance::call(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1289
    #12 0xfaaf88d in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:883
    #13 0xfd1ebd0 in Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Callable::CallError&) core/variant_call.cpp:1222
    #14 0x42cdf1d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_function.cpp:1102
    #15 0x41332af in GDScriptInstance::call(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1289
    #16 0xfaaf88d in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:883
    #17 0xfd1ebd0 in Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Callable::CallError&) core/variant_call.cpp:1222
    #18 0x42cdf1d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_function.cpp:1102
    #19 0x41337c8 in GDScriptInstance::call_multilevel(StringName const&, Variant const**, int) modules/gdscript/gdscript.cpp:1305
    #20 0xa4f7e2f in Node::_notification(int) scene/main/node.cpp:63
    #21 0x1a11955 in Node::_notificationv(int, bool) scene/main/node.h:46
    #22 0x1a13dff in CanvasItem::_notificationv(int, bool) scene/2d/canvas_item.h:166
    #23 0xbe7ff4f in Node2D::_notificationv(int, bool) scene/2d/node_2d.h:38
    #24 0xfab01b2 in Object::notification(int, bool) core/object.cpp:913
    #25 0xa61672b in SceneTree::_notify_group_pause(StringName const&, int) scene/main/scene_tree.cpp:988
    #26 0xa606956 in SceneTree::idle(float) scene/main/scene_tree.cpp:527
    #27 0x18a56a8 in Main::iteration() main/main.cpp:2026
    #28 0x17af00c in OS_X11::run() platform/x11/os_x11.cpp:3337
    #29 0x172a869 in main platform/x11/godot_x11.cpp:56

previously allocated by thread T0 here:
    #0 0x7f010935fae8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dae8)
    #1 0x1003cbe9 in Memory::alloc_static(unsigned long, bool) core/os/memory.cpp:82
    #2 0x1003cae8 in operator new(unsigned long, char const*) core/os/memory.cpp:42
    #3 0x30c6176 in Object* ClassDB::creator<OpenSimplexNoise>() core/class_db.h:145
    #4 0xf848122 in ClassDB::instance(StringName const&) core/class_db.cpp:561
    #5 0x410b29a in GDScriptNativeClass::instance() modules/gdscript/gdscript.cpp:84
    #6 0x410ac8d in GDScriptNativeClass::_new() modules/gdscript/gdscript.cpp:71
    #7 0x41c0d0b in MethodBind0R<Variant>::call(Object*, Variant const**, int, Callable::CallError&) core/method_bind.gen.inc:237
    #8 0xfaafd20 in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:903
    #9 0xfd1ebd0 in Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Callable::CallError&) core/variant_call.cpp:1222
    #10 0x42cde9c in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_function.cpp:1099
    #11 0x41332af in GDScriptInstance::call(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1289
    #12 0xfaaf88d in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:883
    #13 0xfd1ebd0 in Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Callable::CallError&) core/variant_call.cpp:1222
    #14 0x42cdf1d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_function.cpp:1102
    #15 0x41332af in GDScriptInstance::call(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1289
    #16 0xfaaf88d in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:883
    #17 0xfd1ebd0 in Variant::call_ptr(StringName const&, Variant const**, int, Variant*, Callable::CallError&) core/variant_call.cpp:1222
    #18 0x42cdf1d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_function.cpp:1102
    #19 0x41337c8 in GDScriptInstance::call_multilevel(StringName const&, Variant const**, int) modules/gdscript/gdscript.cpp:1305
    #20 0xa4f841c in Node::_notification(int) scene/main/node.cpp:72
    #21 0x1a11955 in Node::_notificationv(int, bool) scene/main/node.h:46
    #22 0x1a13dff in CanvasItem::_notificationv(int, bool) scene/2d/canvas_item.h:166
    #23 0xbe7ff4f in Node2D::_notificationv(int, bool) scene/2d/node_2d.h:38
    #24 0xfab01b2 in Object::notification(int, bool) core/object.cpp:913
    #25 0xa61672b in SceneTree::_notify_group_pause(StringName const&, int) scene/main/scene_tree.cpp:988
    #26 0xa604345 in SceneTree::iteration(float) scene/main/scene_tree.cpp:483
    #27 0x18a40af in Main::iteration() main/main.cpp:2001
    #28 0x17af00c in OS_X11::run() platform/x11/os_x11.cpp:3337
    #29 0x172a869 in main platform/x11/godot_x11.cpp:56

Thread T79 created by T0 here:
    #0 0x7f010928c805 in pthread_create (/lib/x86_64-linux-gnu/libasan.so.5+0x3a805)
    #1 0x61a5fa8 in ThreadPosix::create_func_posix(void (*)(void*), void*, Thread::Settings const&) drivers/unix/thread_posix.cpp:90
    #2 0x10051519 in Thread::create(void (*)(void*), void*, Thread::Settings const&) core/os/thread.cpp:51
    #3 0x30cf9d8 in NoiseTexture::_update_texture() modules/opensimplex/noise_texture.cpp:169
    #4 0x1b88532 in MethodBind0::call(Object*, Variant const**, int, Callable::CallError&) core/method_bind.gen.inc:59
    #5 0xfaafd20 in Object::call(StringName const&, Variant const**, int, Callable::CallError&) core/object.cpp:903
    #6 0xf82483e in Callable::call(Variant const**, int, Variant&, Callable::CallError&) const core/callable.cpp:52
    #7 0xfa7b018 in MessageQueue::_call_function(Callable const&, Variant const*, int, bool) core/message_queue.cpp:253
    #8 0xfa7c0e7 in MessageQueue::flush() core/message_queue.cpp:303
    #9 0xa6044bb in SceneTree::iteration(float) scene/main/scene_tree.cpp:485
    #10 0x18a40af in Main::iteration() main/main.cpp:2001
    #11 0x17af00c in OS_X11::run() platform/x11/os_x11.cpp:3337
    #12 0x172a869 in main platform/x11/godot_x11.cpp:56
    #13 0x7f01080d91e2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x271e2)

Steps to reproduce: Run Project

Minimal reproduction project: The-worst-Godot-test-project.zip

akien-mga commented 4 years ago

CC @JFonS

lupoDharkael commented 4 years ago

This is a race condition that occurs when set_noise(Ref p_noise) is called to set a new noise while _thread_function() is executing for the noise about to be deleted due to the allocation of the new noise in that Ref.

lupoDharkael commented 4 years ago

Is this a good way to prevent this? I'd like to make a PR but I'm not sure about the solution.


index ec67030a65..fbb1eb5616 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -137,14 +137,17 @@ void NoiseTexture::_queue_update() {

 Ref<Image> NoiseTexture::_generate_texture() {

-       if (noise.is_null()) return Ref<Image>();
+       // Prevent memdelete due to unref() on other thread.
+       Ref<OpenSimplexNoise> ref_noise = noise;
+
+       if (ref_noise.is_null()) return Ref<Image>();

        Ref<Image> image;

        if (seamless) {
-               image = noise->get_seamless_image(size.x);
+               image = ref_noise->get_seamless_image(size.x);
        } else {
-               image = noise->get_image(size.x, size.y);
+               image = ref_noise->get_image(size.x, size.y);
        }

        if (as_normalmap) {