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
Linux x64: segfault by Unity/Mono #1708
Comments
Crash when calling |
I am not able to change the software in question as it is proprietary and not updated any more. |
If you look at line |
Thank you for the ideas on where to start looking. With lots of difficulties, I managed to compile a libMonoPosixHelper.so from the Unity Mono repository. And by changing a few lines, the segfault can be avoided. Alloc/free functions were indeed the culprit.
I'd still like to point out though that I hacked a proprietary software (video game) that was working with an outdated (buggy) library. zlib (not ng!) would not expose this bug, while zlib-ng does! |
Apparently deflateInit2 from zlib and zlib-ng have a different defaults when 0 is passed for the alloc/free functions in the z_stream object. So when the alloc/free functions are only set later in the z_stream object, it does not matter with zlib, but crashes zlib-ng |
This is a bug in the proprietary library, even with zlib. Check out this entry in the zlib manual The fact that it doesn't cause an issue with zlib is simply luck. If you used allocators that were picky and needed matched frees, you'd be in a similar boat. It just so happens we have a custom aligned free in the event that you setup a custom allocator so that we can guarantee alignment even when your allocator won't. But, we need to know at library initialization time to handle it. |
Do you know what z_alloc and z_free are defined as in this code? If it happens to be the zlib wrappers for alloc and free and it's a superfluous assignment, we might be able to get around this by comparing the function pointers. Ah, found the repo, they are functions that wrap glib allocators. Yeah, this is...annoying. I don't know how backward to bend, here. |
There has been a lot of discussion about differences between zlib and zlib-ng... Maybe we need to make it (even) more clear in the porting guide that some "broken" use of zlib API will need further fixing to be compatible with improvements in zlib-ng... What comes to modern Linux distributions replacing zlib with zlib-ng, as long as "broken" libraries have source code available, it's only matter of packaging the fixed binary and setting minimum required version in the package metadata (either rpm or deb for most of Linux distributions). This obviously applies mostly to zlib-ng built in compatibility mode, as otherwise the whole executable needs to be rebuilt to use zlib-ng instead of "stock" zlib. |
Avoids segfault when working with zlib-ng. See: zlib-ng/zlib-ng#1708
@jo-oe thanks for notifying mono so they can fix it on their end. I'm not sure what to do about the downstream consumers that are very unlikely to repackage fixed binaries such as those leveraging Unity for games. |
I only realised a bit later that it is apparently the bundled mono library that is actually the culprit. Simply replacing the bundled libMonoPosixHelper.so with a fixed version (see my pr in the mono repo above) works. I will also try to notify the game's distributor, but I doubt they will update ... |
Thanks everyone for your help! I'm just some amateur programmer so I'm quite proud I could find the problem and (apparently ...) fix it :) |
We're here to help people use zlib-ng... Not all issues are bugs in zlib-ng itself, but we still try to help figuring out the root cause. |
One possible "workaround" is to compare distance between the two pointers inside |
It sounds like you’re considering subtracting function pointer values. The C standard only allows pointer arithmetic ( For function pointers or for possibly-unrelated data pointers, all you are permitted to do is compare them for equality ( Anything else is undefined behavior. You can avoid the undefined behavior by converting to |
I just saw #1710. At a glance, it does appear to avoid undefined behavior (as long as the conversion to Maybe the |
If the result of conversion would be negative, it would mean that zlib-ng is used from kernel space... You can't cross boundary of user and kernel space in same allocation. The reason it needs to use signed type is because the original pointer can't be on higher address than the adjusted pointer after aligning the start of allocation. As mentioned in the pull request, modern compilers can optimize the two tests to compare only higher-most bits and discard the lowest 7 bits. |
Valheim is also affected by this, and is also a Unity game. I'm not sure what Unity version they use, but it seems like this could affect all Unity games? I did try testing PR #1713 and that resolved the issue for me. |
Re: casting to |
Does |
I haven't tried this, but I don't think it would help. IIUC the problem is that GCC does alias analysis on RTL level, where casts and memcpy()s may be optimized out, but C-like rules still apply, e.g., two symbols can't point to the same memory. I just checked a very simple example:
and already in The bug I linked is, of course, a very narrow problem related to global variables, but it shows how subtracting unrelated pointers can backfire, even if precautions are taken. |
Replacing zlib with the zlib-ng compatibility library consistently causes a segfault in the game "Kerbal Space Program" (built on Unity 2019.4) in certain situations.
Coredump backtrace:
(Sorry, this is a proprietary app, so several symbols do not have debug information.)
System:
GNU/Linux / Fedora 40 (Beta) / Kernel 6.8.4
CPU: AMD Ryzen 7 7840HS
Please tell me what further information I can provide.
The text was updated successfully, but these errors were encountered: