godotengine / godot

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

SVG loader crash when loading specific icon from the AssetLibrary #97078

Closed SaracenOne closed 1 day ago

SaracenOne commented 2 days ago

Tested versions

6681f2563b99e14929a8acb27f4908fece398ef1

System information

Windows 11

Issue description

The editor will hard crash when browsing the AssetLibrary. It appears to be caused by a ThorVG parsing error with the icon for Gnumaru's Scene Tree View Buttons (https://godotengine.org/asset-library/asset/3063) addon where it will encounter a nullptr. It's unclear at the moment if this is a bug we have to fix or something that need to pass onto the ThorVG developers (or perhaps we just need to update the library), but I don't see anything currently in our implementation of the addon which looks obviously incorrect.

Steps to reproduce

Minimal reproduction project (MRP)

N/A

akien-mga commented 2 days ago

I confirm the crash in latest master, including with #97079. Backtrace with thorvg 0.14.10 from that PR:

================================================================
handle_crash: Program crashed with signal 11
Engine version: Godot Engine v4.4.dev.custom_build (3e0ba54a7951894adbd3cc9b430936743f65d8e6)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib64/libc.so.6(+0x40d00) [0x7fa3546ffd00] (??:0)
[2] tvg::Task::done() (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h:51)
[3] SwTask::bounds() (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp:57)
[4] tvg::SwRenderer::region(void*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp:505)
[5] tvg::Shape::Impl::bounds(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgShape.h:121)
[6] tvg::Text::Impl::bounds(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgText.h:88)
[7] tvg::Paint::Impl::bounds(tvg::RenderMethod*) const (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:141 (discriminator 5))
[8] tvg::Scene::Impl::bounds(tvg::RenderMethod*) const (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:149)
[9] tvg::Paint::Impl::bounds(tvg::RenderMethod*) const (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:141 (discriminator 3))
[10] tvg::Scene::Impl::bounds(tvg::RenderMethod*) const (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:149)
[11] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:126 (discriminator 1))
[12] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[13] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:131 (discriminator 1))
[14] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[15] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:131 (discriminator 1))
[16] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[17] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:131 (discriminator 1))
[18] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[19] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:131 (discriminator 1))
[20] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[21] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:131 (discriminator 1))
[22] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[23] tvg::Scene::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgScene.h:131 (discriminator 1))
[24] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 3))
[25] tvg::Picture::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPicture.cpp:85)
[26] tvg::Paint::Impl::render(tvg::RenderMethod*) (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgPaint.cpp:229 (discriminator 4))
[27] tvg::Canvas::Impl::draw() (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgCanvas.h:116 (discriminator 1))
[28] tvg::Canvas::draw() (/home/akien/Godot/godot/thirdparty/thorvg/src/renderer/tvgCanvas.cpp:67)
[29] ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image>, unsigned char const*, int, float, bool) (/home/akien/Godot/godot/modules/svg/image_loader_svg.cpp:122 (discriminator 1))
[30] ImageLoaderSVG::load_mem_svg(unsigned char const*, int, float) (/home/akien/Godot/godot/modules/svg/image_loader_svg.cpp:74 (discriminator 1))
[31] EditorAssetLibrary::_image_update(bool, bool, Vector<unsigned char> const&, int) (/home/akien/Godot/godot/./editor/plugins/asset_library_editor_plugin.cpp:854 (discriminator 1))
[32] EditorAssetLibrary::_request_image(ObjectID, int, String, EditorAssetLibrary::ImageType, int) (/home/akien/Godot/godot/./editor/plugins/asset_library_editor_plugin.cpp:1027 (discriminator 2))
[33] EditorAssetLibrary::_http_request_completed(int, int, Vector<String> const&, Vector<unsigned char> const&) (/home/akien/Godot/godot/./editor/plugins/asset_library_editor_plugin.cpp:1401 (discriminator 8))
[34] void call_with_variant_args_helper<EditorAssetLibrary, int, int, Vector<String> const&, Vector<unsigned char> const&, 0ul, 1ul, 2ul, 3ul>(EditorAssetLibrary*, void (EditorAssetLibrary::*)(int, int, Vector<String> const&, Vector<unsigned char> const&), Variant const**, Callable::CallError&, IndexSequence<0ul, 1ul, 2ul, 3ul>) (/home/akien/Godot/godot/./core/variant/binder_common.h:304 (discriminator 5))
[35] void call_with_variant_args<EditorAssetLibrary, int, int, Vector<String> const&, Vector<unsigned char> const&>(EditorAssetLibrary*, void (EditorAssetLibrary::*)(int, int, Vector<String> const&, Vector<unsigned char> const&), Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./core/variant/binder_common.h:419)
[36] CallableCustomMethodPointer<EditorAssetLibrary, int, int, Vector<String> const&, Vector<unsigned char> const&>::call(Variant const**, int, Variant&, Callable::CallError&) const (/home/akien/Godot/godot/./core/object/callable_method_pointer.h:104)
[37] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/home/akien/Godot/godot/./core/variant/callable.cpp:57)
[38] Object::emit_signalp(StringName const&, Variant const**, int) (/home/akien/Godot/godot/./core/object/object.cpp:1201)
[39] Node::emit_signalp(StringName const&, Variant const**, int) (/home/akien/Godot/godot/./scene/main/node.cpp:3927)
[40] Error Object::emit_signal<int, int, Vector<String>, Vector<unsigned char> >(StringName const&, int, int, Vector<String>, Vector<unsigned char>) (/home/akien/Godot/godot/./core/object/object.h:919)
[41] HTTPRequest::_request_done(int, int, Vector<String> const&, Vector<unsigned char> const&) (/home/akien/Godot/godot/./scene/main/http_request.cpp:483 (discriminator 4))
[42] void call_with_variant_args_helper<HTTPRequest, int, int, Vector<String> const&, Vector<unsigned char> const&, 0ul, 1ul, 2ul, 3ul>(HTTPRequest*, void (HTTPRequest::*)(int, int, Vector<String> const&, Vector<unsigned char> const&), Variant const**, Callable::CallError&, IndexSequence<0ul, 1ul, 2ul, 3ul>) (/home/akien/Godot/godot/./core/variant/binder_common.h:304 (discriminator 5))
[43] void call_with_variant_args<HTTPRequest, int, int, Vector<String> const&, Vector<unsigned char> const&>(HTTPRequest*, void (HTTPRequest::*)(int, int, Vector<String> const&, Vector<unsigned char> const&), Variant const**, int, Callable::CallError&) (/home/akien/Godot/godot/./core/variant/binder_common.h:419)
[44] CallableCustomMethodPointer<HTTPRequest, int, int, Vector<String> const&, Vector<unsigned char> const&>::call(Variant const**, int, Variant&, Callable::CallError&) const (/home/akien/Godot/godot/./core/object/callable_method_pointer.h:104)
[45] Callable::callp(Variant const**, int, Variant&, Callable::CallError&) const (/home/akien/Godot/godot/./core/variant/callable.cpp:57)
[46] CallQueue::_call_function(Callable const&, Variant const*, int, bool) (/home/akien/Godot/godot/./core/object/message_queue.cpp:221)
[47] CallQueue::flush() (/home/akien/Godot/godot/./core/object/message_queue.cpp:270)
[48] SceneTree::process(double) (/home/akien/Godot/godot/./scene/main/scene_tree.cpp:578)
[49] Main::iteration() (/home/akien/Godot/godot/main/main.cpp:4350 (discriminator 3))
[50] OS_LinuxBSD::run() (/home/akien/Godot/godot/platform/linuxbsd/os_linuxbsd.cpp:962 (discriminator 1))
[51] /home/akien/Godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x14b) [0x5df7c71] (/home/akien/Godot/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[52] /lib64/libc.so.6(+0x2a088) [0x7fa3546e9088] (??:0)
[53] /lib64/libc.so.6(__libc_start_main+0x8b) [0x7fa3546e914b] (??:0)
[54] /home/akien/Godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5df7a65] (??:?)
-- END OF BACKTRACE --
================================================================
timothyqiu commented 2 days ago

To reproduce the crash, you can also run the script below with godot --headless -s /path/to/script.gd.

MRP Script with the original SVG ```gdscript extends SceneTree const SVG = """ ギヌ """ func _process(delta: float) -> bool: var image := Image.new() print(image.load_svg_from_string(SVG)) return true ```

It seems that it's these elements in the SVG that's causing the crash.

<g opacity="0.2">
    <g transform="matrix(1,0,0,1,-1391.95,-34.4526)">
        <text x="604.182px" y="875.692px" style="font-family:'MalgunGothic', 'Malgun Gothic', sans-serif;font-size:100px;fill:white;">丸</text>
    </g>
    <g transform="matrix(1,0,0,1,-1534.54,-5.26182)">
        <text x="698.727px" y="764.177px" style="font-family:'MalgunGothic', 'Malgun Gothic', sans-serif;font-size:100px;fill:white;">ギヌ</text>
    </g>
</g>

The image loads successfully after removing these lines. The opacity is necessary to reproduce the crash.

MRP Script with Minimal SVG ```gdscript extends SceneTree const SVG = """ ギヌ """ func _process(delta: float) -> bool: var image := Image.new() print(image.load_svg_from_string(SVG)) return true ```
akien-mga commented 2 days ago

CC @capnm

akien-mga commented 2 days ago

I tested earlier thorvg versions (in Godot), the regression starts with 0.14.7.

akien-mga commented 2 days ago

I tested earlier thorvg versions (in Godot), the regression starts with 0.14.7.

Bisected the regression to https://github.com/thorvg/thorvg/commit/f5337015e971d24379d2ee664895503ab8945e13 (cc @hermet). I'll file an upstream bug report tomorrow.

hermet commented 1 day ago

@akien-mga Hello, the fix will be in the next release. Thanks!

akien-mga commented 1 day ago

Awesome, thanks!