Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Executing Image.save_jpg_to_buffer function crashes Godot #84707

Closed
qarmin opened this issue Nov 10, 2023 · 0 comments · Fixed by #84758
Closed

Executing Image.save_jpg_to_buffer function crashes Godot #84707

qarmin opened this issue Nov 10, 2023 · 0 comments · Fixed by #84758

Comments

@qarmin
Copy link
Contributor

qarmin commented Nov 10, 2023

Godot version

4.2.beta.custom_build. 9df6491

System information

Ubuntu 22.04 CI

Issue description

When executing (this code was automatically minimized, so it is possible, that an even more "minimal" project can be created)

extends Node
func _process(delta):
	var temp_variable18110 = CSGCylinder3D.new()
	add_child(temp_variable18110)
	temp_variable18110.queue_free()
	var temp_variable18237 = Image.new()
	temp_variable18237.copy_from(null)
	temp_variable18237._set_data({})
	temp_variable18237.is_empty()
	temp_variable18237.crop(17, 65)
	temp_variable18237.compress_from_channels(1, 91, -89)
	temp_variable18237.get_height()
	temp_variable18237.save_jpg_to_buffer(36.2883925437927)

Godot crashes:

Godot Engine v4.2.beta.custom_build.9df649185 - https://godotengine.org
Vulkan API 1.2.0 - Forward Mobile - Using Vulkan Device #0: Unknown - SwiftShader Device (LLVM 10.0.0)
drivers/vulkan/rendering_device_vulkan.cpp:4880:63: runtime error: reference binding to misaligned address 0x619000138d9c for type 'const struct 
==15714==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6190018aeb90 at pc 0x560d84990f5d bp 0x7fff06afa000 sp 0x7fff06af9ff0
READ of size 1 at 0x6190018aeb90 thread T0
    #0 0x560d84990f5c in RGB_to_YCC thirdparty/jpeg-compressor/jpge.cpp:96
    #1 0x560d849aa33b in jpge::jpeg_encoder::load_mcu(void const*) thirdparty/jpeg-compressor/jpge.cpp:861
    #2 0x560d849abcc8 in jpge::jpeg_encoder::process_scanline(void const*) thirdparty/jpeg-compressor/jpge.cpp:929
    #3 0x560d8498ec64 in _jpgd_save_to_output_stream modules/jpg/image_loader_jpegd.cpp:172
    #4 0x560d8498f119 in _jpgd_buffer_save_func modules/jpg/image_loader_jpegd.cpp:184
    #5 0x560d9aed5e7f in Image::save_jpg_to_buffer(float) const core/io/image.cpp:2545
    #6 0x560d9afc9d28 in void call_with_variant_args_retc_helper<__UnexistingClass, Vector<unsigned char>, float, 0ul>(__UnexistingClass*, Vector<unsigned char> (__UnexistingClass::*)(float) const, Variant const**, Variant&, Callable::CallError&, IndexSequence<0ul>) core/variant/binder_common.h:806
    #7 0x560d9afaed87 in void call_with_variant_args_retc_dv<__UnexistingClass, Vector<unsigned char>, float>(__UnexistingClass*, Vector<unsigned char> (__UnexistingClass::*)(float) const, Variant const**, int, Variant&, Callable::CallError&, Vector<Variant> const&) core/variant/binder_common.h:567
    #8 0x560d9af997c3 in MethodBindTRC<Vector<unsigned char>, float>::call(Object*, Variant const**, int, Callable::CallError&) const core/object/method_bind.h:583
    #9 0x560d9c30cca0 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) core/object/object.cpp:775
    #10 0x560d9b6c11ce in Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) core/variant/variant_call.cpp:1168
    #11 0x560d8300b45d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_vm.cpp:1704
    #12 0x560d829050b4 in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1896
    #13 0x560d900cbad0 in bool Node::_gdvirtual__process_call<false>(double) scene/main/node.h:318
    #14 0x560d9000a2c0 in Node::_notification(int) scene/main/node.cpp:57
    #15 0x560d82415863 in Node::_notificationv(int, bool) scene/main/node.h:49
    #16 0x560d9c30e82a in Object::notification(int, bool) core/object/object.cpp:837
    #17 0x560d901c9c92 in SceneTree::_process_group(SceneTree::ProcessGroup*, bool) scene/main/scene_tree.cpp:951
    #18 0x560d901ccf36 in SceneTree::_process(bool) scene/main/scene_tree.cpp:1028
    #19 0x560d901bb02c in SceneTree::process(double) scene/main/scene_tree.cpp:508
    #20 0x560d81a532f1 in Main::iteration() main/main.cpp:3636
    #21 0x560d8176b225 in OS_LinuxBSD::run() platform/linuxbsd/os_linuxbsd.cpp:933
    #22 0x560d81749757 in main platform/linuxbsd/godot_linuxbsd.cpp:74
    #23 0x7fc576629d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
    #24 0x7fc576629e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
    #25 0x560d81749104 in _start (/home/runner/work/Qarminer/Qarminer/godot.linuxbsd.editor.dev.x86_64.san+0x3a273104)
0x6190018aeb90 is located 0 bytes to the right of 1040-byte region [0x6190018ae780,0x6190018aeb90)
allocated by thread T0 here:
    #0 0x7fc5772b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x560d9a9bc207 in Memory::alloc_static(unsigned long, bool) core/os/memory.cpp:75
    #2 0x560d818effc2 in Error CowData<unsigned char>::resize<false>(int) core/templates/cowdata.h:291
    #3 0x560d818cd165 in Vector<unsigned char>::resize(int) core/templates/vector.h:94
    #4 0x560d8286639e in _compress_etcpak(EtcpakType, Image*) modules/etcpak/image_compress_etcpak.cpp:176
    #5 0x560d82864d75 in _compress_etc1(Image*) modules/etcpak/image_compress_etcpak.cpp:78
    #6 0x560d9aed89c8 in Image::compress_from_channels(Image::CompressMode, Image::UsedChannels, Image::ASTCFormat) core/io/image.cpp:2654
    #7 0x560d9afc21ac in void call_with_variant_args_ret_helper<__UnexistingClass, Error, Image::CompressMode, Image::UsedChannels, Image::ASTCFormat, 0ul, 1ul, 2ul>(__UnexistingClass*, Error (__UnexistingClass::*)(Image::CompressMode, Image::UsedChannels, Image::ASTCFormat), Variant const**, Variant&, Callable::CallError&, IndexSequence<0ul, 1ul, 2ul>) core/variant/binder_common.h:755
    #8 0x560d9afa8779 in void call_with_variant_args_ret_dv<__UnexistingClass, Error, Image::CompressMode, Image::UsedChannels, Image::ASTCFormat>(__UnexistingClass*, Error (__UnexistingClass::*)(Image::CompressMode, Image::UsedChannels, Image::ASTCFormat), Variant const**, int, Variant&, Callable::CallError&, Vector<Variant> const&) core/variant/binder_common.h:534
    #9 0x560d9af95053 in MethodBindTR<Error, Image::CompressMode, Image::UsedChannels, Image::ASTCFormat>::call(Object*, Variant const**, int, Callable::CallError&) const core/object/method_bind.h:496
    #10 0x560d9c30cca0 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) core/object/object.cpp:775
    #11 0x560d9b6c11ce in Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) core/variant/variant_call.cpp:1168
    #12 0x560d8300b45d in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_vm.cpp:1704
    #13 0x560d829050b4 in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1896
    #14 0x560d900cbad0 in bool Node::_gdvirtual__process_call<false>(double) scene/main/node.h:318
    #15 0x560d9000a2c0 in Node::_notification(int) scene/main/node.cpp:57
    #16 0x560d82415863 in Node::_notificationv(int, bool) scene/main/node.h:49
    #17 0x560d9c30e82a in Object::notification(int, bool) core/object/object.cpp:837
    #18 0x560d901c9c92 in SceneTree::_process_group(SceneTree::ProcessGroup*, bool) scene/main/scene_tree.cpp:951
    #19 0x560d901ccf36 in SceneTree::_process(bool) scene/main/scene_tree.cpp:1028
    #20 0x560d901bb02c in SceneTree::process(double) scene/main/scene_tree.cpp:508
    #21 0x560d81a532f1 in Main::iteration() main/main.cpp:3636
    #22 0x560d8176b225 in OS_LinuxBSD::run() platform/linuxbsd/os_linuxbsd.cpp:933
    #23 0x560d81749757 in main platform/linuxbsd/godot_linuxbsd.cpp:74
    #24 0x7fc576629d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
SUMMARY: AddressSanitizer: heap-buffer-overflow thirdparty/jpeg-compressor/jpge.cpp:96 in RGB_to_YCC
Shadow bytes around the buggy address:
  0x0c328030dd20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030dd30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030dd40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030dd50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030dd60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c328030dd70: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c328030dd80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c328030dd90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030dda0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030ddb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c328030ddc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==15714==ABORTING

This example was found by Godot fuzzer - Qarminer, so it is quite unlikelly that this code could be used in real project, but still this should be handled gracefully.

Memory leaks or asan backtraces are visible when using Godot build with sanitizers support - https://github.com/qarmin/GodotBuilds/actions (linux -> linux-editor-sanitizers)

Steps to reproduce

Above

Minimal reproduction project

Above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants