A Linux gamer takes aim at Unity

Workaround for black screen in Unity games under Linux with glibc 2.25

The smell of a new The GNU C Library (glibc) release … it’s the smell of software compatibility issues! This time, as so many times before, it has badly affected proprietary games released for Linux. The glibc mentality of “let’s just recompile all the things so they work with our library” doesn’t work for software that isn’t released in source format. Here is how you work around a problem that causes all games using the Unity Engine to stall on a black screen after launch.

glibc is a library used in almost all programs and among other things contain functions for working with multi-threaded programs, files, and memory management. In version 2.25, a change to the thread-local storage (TLS) model in glibc caused an incompatibility with the Unity 3D game engine. —or actually, the issue looks to be with Mono, a library from cross-platform .Net development, as distributed with many Unity games for Linux. I’m not entirely sure exactly what broke and where, but I do know how you can work around the problem.

Version 2.25 of glibc is shipping in Arch Linux, Fedora 26, and openSUSE tumbleweed.

Affected games

The bug affects 64-bit games built on the Unity Engine 5.6 and older with glibc version 2.25 on a 64-bit operating system. 32-bit games running on a 64-bit operating system are not affected.

Affected games get stuck on a black screen. The mouse cursor is visible, often skinned by the game, but you can’t do much more than play cat and mouse with the cursor.

Here is an incomplete list of affected games:

  • Besiege
  • Cities Skylines
  • Enter the Gungeon
  • Firewatch
  • Gone Home
  • Hatoful Boyfriend
  • Mini Metro
  • RimWorld
  • Robocraft
  • Superhot

The workaround

One of the fun things about Linux, not that I’m suggesting that anything about this bug is fun, is that you can often solve problems yourself. In this instance, we have a problem with memory allocation (malloc) in glibc causing problems for a multi-threaded program. As a stop-gap solution until the Unity Engine/Mono can resolve this issue and until game developers start shipping updated version of these, you can simply use another malloc implementation.

You can install jemalloc from your package repository and then run Steam, or individual games, using it rather than glibc’s malloc implementation.

  1. Install jemalloc from your package repository. Here are commands for popular distributions:

    # Fedora
    dnf install jemalloc
    # Debian / Ubuntu
    apt-get install libjemalloc1
    # openSUSE
    zypper install libjemalloc2

This installs the jemalloc libraries. The next steps is to actually use the libraries. Until this is resolved, launch Steam — or the game executable directly — prefixed with an environmental variable causing libjemalloc to be loaded before — and thus be preferred over — glibc’s malloc implementation.

  1. Start Steam or your game binaries directly with instructions to preload jemalloc. This example demonstrates how to open Steam (and any game started from it) with this library:

    # Fedora / openSUSE
    LD_PRELOAD=/usr/lib64/libjemalloc.so.2 steam
    # Debian / Ubuntu
    LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1 steam

You should periodically try loading your games without the LD_PRELOAD. Eventually, this bug will be resolved and your games with be updated to run with glibc’s version of malloc again. Some games may never be updated, so you may need to use this workaround for quite a while. You shouldn’t notice any difference running a game with libjemalloc instead of glibc. However, unexpected incompatibility issues can occur when running this somewhat unusual setup.

If you start Steam, as suggested above, you may get an error stating that “ERROR: ld.so: object ‘/usr/lib64/libjemalloc.so.2’ from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS64): ignored.”. This error simply says that you tried loading a 64-bit library in a 32-bit application (Steam is 32-bit only). You can safely ignore this error. The LD_PRELOAD variable will be inherited by any subprocess/games you start from Steam, causing them to use the variable.