Skip to content

Weird munmap_chunk(): invalid pointer crash when freeing pic in R_FindImageFile() #1598

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

Open
illwieckz opened this issue Mar 13, 2025 · 2 comments

Comments

@illwieckz
Copy link
Member

illwieckz commented Mar 13, 2025

I noticed a very weird munmap_chunk(): invalid pointer crash when freeing pic in R_FindImageFile():

Z_Free( *pic );

I only reproduce it when testing on a very low end Raspberry PI 3. For example I don't reproduce it on my amd64 workstation, and I don't reproduce it on an orangepi5 board which is also arm64 like the rpi3, but more powerful.

At first I thought this could be some memory being missing, or other problems being caused by the fact such hardware is very low end.

But then I noticed the crash happened when freeing something. This is not caused by using a very old OpenGL. This is even not caused by the memory being to small.

The things is that if I comment out the Z_Free( *pic ); line, the bug is gone and the game runs, while actually consuming more memory!

I then suspected that we may have some memory corruption somewhere, and that under the specific conditions of that hardware it actually breaks something. But I always get that error when loading the gfx/weapons/flamer/haze_n image, not on other images loaded before it. This looks very reproducible for a memory corruption, I always reproduce it, and always at the same place whatever the build I use (Debug, MinSizeRel, running on debugger or not, using different HunkMeg sizes…).

So, I don't know what is happening. But Z_Free() which just calls standard free() is falling here.

I've checked it with some printf(), but the pointer is never null when it fails.

Also, pic is passed as const on functions called prior the Z_Free() call, so it is very unlikely that the pointer get modified because of a bug.

Also, the pointer address never changes once set, I've checked with some printf().

I remember it worked before 0.55.2 was released (I have not yet tested the 0.55.2 release).

Debug: Found CRN image candidate 'gfx/weapons/flamer/smoke': gfx/weapons/flamer/smoke.crn 
Debug: Found 256×256 CRN image 'gfx/weapons/flamer/smoke': gfx/weapons/flamer/smoke.crn 
Debug: Creating image gfx/weapons/flamer/smoke (256×256, 9 mips) 
Debug: Allocating image gfx/weapons/flamer/smoke 
Debug: Uploading image gfx/weapons/flamer/smoke (128×128, 1 layers, 0xde1 type, 0x83f3 format) 
Debug: Found CRN image candidate 'gfx/weapons/flamer/haze_n': gfx/weapons/flamer/haze_n.crn 
Debug: Found 128×128 CRN image 'gfx/weapons/flamer/haze_n': gfx/weapons/flamer/haze_n.crn 
Debug: Creating image gfx/weapons/flamer/haze_n (128×128, 8 mips) 
Debug: Allocating image gfx/weapons/flamer/haze_n 
Debug: Uploading image gfx/weapons/flamer/haze_n (128×128, 1 layers, 0xde1 type, 0x83f3 format) 
]munmap_chunk(): invalid pointer

Thread 1 "daemon" received signal SIGABRT, Aborted.
0x0000fffff71d09f0 in ?? () from /lib/aarch64-linux-gnu/libc.so.6
(gdb) bt
#0  0x0000fffff71d09f0 in ?? () from /lib/aarch64-linux-gnu/libc.so.6
#1  0x0000fffff718a72c in raise () from /lib/aarch64-linux-gnu/libc.so.6
#2  0x0000fffff717747c in abort () from /lib/aarch64-linux-gnu/libc.so.6
#3  0x0000fffff71c4aac in ?? () from /lib/aarch64-linux-gnu/libc.so.6
#4  0x0000fffff71dae4c in ?? () from /lib/aarch64-linux-gnu/libc.so.6
#5  0x0000fffff71db04c in ?? () from /lib/aarch64-linux-gnu/libc.so.6
#6  0x0000fffff71df6a4 in free () from /lib/aarch64-linux-gnu/libc.so.6
#7  0x0000aaaaaabc049c in Z_Free (ptr=<optimized out>, ptr=<optimized out>)
    at /src/engine/qcommon/qcommon.h:582
#8  R_FindImageFile (imageName=<optimized out>, imageParams=...)
    at /src/engine/renderer/tr_image.cpp:1863
#9  0x0000aaaaaabea2d0 in LoadMap (stage=stage@entry=0xaaaaabbe0d38 <_ZL6stages.lto_priv.0>, buffer=<optimized out>, 
    buffer@entry=0xfffffffece70 "gfx/weapons/flamer/haze_n", type=<optimized out>, bundleIndex=bundleIndex@entry=0)
    at /src/engine/renderer/tr_shader.cpp:1534
#10 0x0000aaaaaabecc30 in ParseStage (stage=<optimized out>, text=0xfffffffed730)
    at /src/engine/renderer/tr_shader.cpp:3284
#11 0x0000aaaaaabf0898 in ParseShader (_text=<optimized out>)
    at /src/engine/renderer/tr_shader.cpp:3862
#12 R_FindShader (name=<optimized out>, name@entry=0xaaaaad910bd0 "gfx/weapons/flamer/haze", 
    type=type@entry=shaderType_t::SHADER_2D, flags=flags@entry=64)
    at /src/engine/renderer/tr_shader.cpp:6248
#13 0x0000aaaaaabf2a48 in RE_RegisterShader (name=0xaaaaad910bd0 "gfx/weapons/flamer/haze", flags=64)
    at /src/engine/renderer/tr_shader.cpp:6455
#14 0x0000aaaaaac867d8 in operator() (handle=@0xfffffffedc28: 0, flags=<optimized out>, 
    name="gfx/weapons/flamer/haze", __closure=<optimized out>)
    at /src/engine/client/cl_cgame.cpp:1262
#15 Util::apply_impl<CGameVM::QVMSyscall(int, Util::Reader&, IPC::Channel&)::<lambda(const std::string&, int, int&)>, std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, int&&, int&>, 0, 1, 2> (
    func=..., tuple=...) at /src/common/Util.h:136
#16 Util::apply<CGameVM::QVMSyscall(int, Util::Reader&, IPC::Channel&)::<lambda(const std::string&, int, int&)>, std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, int&&, int&> > (tuple=..., 
    func=...) at /src/common/Util.h:141
#17 IPC::detail::HandleMsg<CGameVM::QVMSyscall(int, Util::Reader&, IPC::Channel&)::<lambda(const std::string&, int, int&)>, IPC::Message<IPC::Id<0, 37>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, IPC::Reply<int> > (func=..., reader=..., channel=...)
    at /src/common/IPC/Channel.h:217
#18 IPC::HandleMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)37>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, IPC::Reply<int> >, CGameVM::QVMSyscall(int, Util::Reader&, IPC::Channel&)::{lambda(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int, int&)#22}>(IPC::Channel&, Util::Reader, CGameVM::QVMSyscall(int, Util::Reader&, IPC::Channel&)::{lambda(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int, int&)#22}&&) [clone .isra.0] (
    channel=..., reader=..., func=...)
    at /src/common/IPC/Channel.h:241
#19 0x0000aaaaaac67ba8 in CGameVM::QVMSyscall(int, Util::Reader&, IPC::Channel&) [clone .constprop.0] (
    syscallNum=<optimized out>, reader=..., channel=..., this=<optimized out>)
    at /src/engine/client/cl_cgame.cpp:1261
#20 0x0000aaaaaab22f84 in CGameVM::Syscall (this=0xaaaaaad61748 <cgvm>, id=<optimized out>, reader=..., channel=...)
    at /src/engine/client/cl_cgame.cpp:1066
#21 0x0000aaaaaac777d8 in VM::VMBase::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)0>, int>, IPC::Reply<> >, int>(int&&)::{lambda(unsigned int, Util::Reader)#1}::operator()(unsigned int, Util::Reader) (
    reader=..., id=37, __closure=0xfffffffee430)
    at /src/engine/framework/VirtualMachine.h:138
#22 IPC::detail::SendMsg<VM::VMBase::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&)::{lambda(unsigned int, Util::Reader)#1}&, IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<>, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(IPC::Channel&, VM::VMBase::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&)::{lambda(unsigned int, Util::Reader)#1}&, IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&) [clone .constprop.0]
    (messageHandler=..., channel=...)
    at /src/common/IPC/Channel.h:174
#23 0x0000aaaaaab1a784 in IPC::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, VM::VMBase::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&)::{lambda(unsigned int, Util::Reader)#1}, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(IPC::Channel&, VM::VMBase::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&)::{lambda(unsigned int, Util::Reader)#1}&&, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&) (messageHandler=..., channel=...)
    at /src/common/IPC/Channel.h:234
#24 VM::VMBase::SendMsg<IPC::SyncMessage<IPC::Message<IPC::Id<(unsigned short)0, (unsigned short)1>, int, int, glconfig_t, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul> >, IPC::Reply<> >, int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&>(int&, int&, glconfig_t&, std::array<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 1024ul>&) (this=<optimized out>)
    at /src/engine/framework/VirtualMachine.h:136
#25 CGameVM::CGameInit (this=<optimized out>, clientNum=<optimized out>, serverMessageNum=8)
    at /src/engine/client/cl_cgame.cpp:977
#26 CL_InitCGame () at /src/engine/client/cl_cgame.cpp:628
#27 0x0000aaaaaab22c78 in CL_DownloadsComplete ()
    at /src/engine/client/cl_download.cpp:109
#28 0x0000aaaaaab3616c in CL_InitDownloads ()
    at /src/engine/client/cl_download.cpp:237
#29 CL_ParseGamestate (msg=msg@entry=0xfffffffeea30)
    at /src/engine/client/cl_parse.cpp:460
#30 0x0000aaaaaab368cc in CL_ParseServerMessage (msg=0xfffffffeea30)
    at /src/engine/client/cl_parse.cpp:570
#31 0x0000aaaaaab2ec9c in CL_PacketEvent (from=..., msg=0xfffffffeea30)
    at /src/engine/client/cl_main.cpp:1946
#32 0x0000aaaaaaaf183c in HandlePacketEvent (event=...)
    at /src/engine/qcommon/common.cpp:393
#33 Com_EventLoop () at /src/engine/qcommon/common.cpp:512
#34 0x0000aaaaaaaf22a8 in Com_Frame ()
    at /src/engine/qcommon/common.cpp:879
#35 0x0000aaaaaaaf4cd4 in Application::ClientApplication::Frame (this=0xaaaaaad605a8 <Application::GetApp()::app>)
    at /src/engine/client/ClientApplication.cpp:110
#36 0x0000aaaaaaad8a18 in Application::Frame ()
    at /src/engine/framework/Application.cpp:87
#37 main (argc=<optimized out>, argv=<optimized out>)
    at /src/engine/framework/System.cpp:1006
@illwieckz illwieckz changed the title Weird crash when freeing pic in R_FindImageFile() Weird munmap_chunk(): invalid pointer crash when freeing pic in R_FindImageFile() Mar 14, 2025
@slipher
Copy link
Member

slipher commented Mar 14, 2025

I've noticed before that some of that code dealing with image arrays is really bad. It's like no one is really keeping track of the number of images in the array; some functions seem to have no limit of images they might add although the array is of fixed size; etc. It would be unsurprising if it does not handle errors correctly.

@VReaperV
Copy link
Contributor

I've noticed before that some of that code dealing with image arrays is really bad. It's like no one is really keeping track of the number of images in the array; some functions seem to have no limit of images they might add although the array is of fixed size; etc. It would be unsurprising if it does not handle errors correctly.

Related: #271.

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

No branches or pull requests

3 participants