mojira.dev
MC-200083

Game hangs when taking screenshot and viewing screenshot

How to reproduce

  1. Open Minecraft in linux

  2. Take a screenshot with F2

  3. Click the underlined text in chat
    → The game will hang until you close the image viewer

Code analysis & fix

Code analysis and fix by @unknown can be found in this comment.

Attachments

Comments 9

Please attach a screenshot from the world with the F3 debug menu enabled.

Thank you very much.

Please, first of all, try to open the "Report Bugs" and/or "Feedback" buttons in the pause menu and check if the game also freezes.

Next, please add the launcher log using these instructions to this ticket - please copy the log after the error has occurred.

Quick Links:
📓 Issue Guidelines – 🛠 Community Support – 📧 Customer Support – ✍️ Feedback and Suggestions – 📖 Game Wiki
💬 Mojira Subreddit – 💬 Mojira Discord

Here is the launcher log. https://paste.ubuntu.com/p/kpx5kF7TqY/

The game does not freeze or crash when clicking on "Report Bugs" or "Feedback". 

I can confirm this behavior on Linux Mint 20 Cinnamon, running vanilla Minecraft 1.16.4 or snapshot 20w51a on OpenJDK 11. When you click a chat link to open an external application (i.e. a screenshot in the system's configured image viewer), the game will stall until that application is closed. It feels like only the UI hangs, as afterwards you get a flood of all the sounds you "missed" while looking at the screenshot.

I could imagine it doesn't happen with web links, because browsers tend to launch the actual UI in a separate process and the originally launched process terminates again after successfully handing off the URL to that UI process. Since that sequence of events completes quite fast and the game is in the pause menu, it's hard to tell, but there definitely is a short hitch in game animations when I open the feedback or bug report link from the in-game menu while on a server (to prevent the game pausing from opening that menu).

As far as logs are concerned, the game doesn't appear to output anything to the log window while all this is going on. The final output for me is the chat message that the screenshot has been saved from pressing F2. Also no additional logs after the image viewer closed and the game resumes.

I can confirm this issue up to 1.16.5 (Linux Mint 20.1 Cinnamon), and while it's relatively unproblematic as the game resumes upon closing the external application, all buttons that open external applications including the "Open Pack Folder" buttons for resource and data packs cause the program interruption. In the 1.17 snapshots (21w03a) Minecraft cannot resume after closing the external program, and instead crashes.

I can confirm this issue on Manjaro. It seems to be a problem with LWJGL 3. Here is a rundown of my tests:

  • Opening screenshot works fine up to 1.12.2.

  • In 17w43b and 17w43a, opening screenshot does not work at all as clicking the chat does nothing. These are the first 1.13 snapshots, and are also the first versions to use LWJGL 3 instead of LWJGL 2.

  • Starting from 17w45a, the bug appears (the game hangs until the image viewer is closed). Opening the resource pack folder freezes the game in the exact same way.

  • 1.13.x, 1.14.x and 1.16.x suffer the same problems as 17w45a

  • The problem remains the same in 1.17 snapshots, I was not able to reproduce any crash (tested with 20w03a and 20w15a).

 

After digging a little deeper it has nothing to do with LWJGL directly and comes down to the way the game incorrectly opens the sub-process that opens the file. I have implemented a fix in this fabic mod.

The game creates a sub-process that runs the relevant command that will open the file (xdg-open on Linux), and then waits to see if that process prints out any error. Relevant vanilla method in net.minecraft.util.OperatingSystem with YARN mappings:

public void open(URL url) {
    try {
        Process process = (Process)AccessController.doPrivileged(() -> {
            return Runtime.getRuntime().exec(this.getURLOpenCommand(url));
        });
        Iterator var3 = IOUtils.readLines(process.getErrorStream()).iterator();

        while(var3.hasNext()) {
            String string = (String)var3.next();
            Util.LOGGER.error(string);
         }

         process.getInputStream().close();
         process.getErrorStream().close();
         process.getOutputStream().close();
    } catch (IOException | PrivilegedActionException var5) {
         Util.LOGGER.error((String)"Couldn't open url '{}'", (Object)url, (Object)var5);
    }
}

The problem here is the while loop: I don't know how the relevant commands behave on other operating systems, but on Linux, xdg-open creates a process that inherits its standard input/output/error streams, meaning that the error stream the while loop is checking will only be closed when the child process exits, hence why the loop freezes the game until you close the image viewer / file viewer / whatever was opened.

The correct way to handle error messages from the child process or the open command would be to used something non-blocking, like making the child inherit the game's output stream using a ProcessBuilder. Example implementation from the mod above:

public void open(URL url) {
    try {
         AccessController.doPrivileged((PrivilegedExceptionAction<Process>)() -> {
              return new ProcessBuilder().command(this.getURLOpenCommand(url)).redirectError(Redirect.INHERIT).start();
         });
    } catch (PrivilegedActionException var5) {
        Util.LOGGER.error((String)"Couldn't open url '{}'", (Object)url, (Object)var5);
    }
}

Affects 1.18.1, and I think it's worth noting that if the photo viewer that Minecraft opens crashes it will take Minecraft with it.

Felis Catus

(Unassigned)

Community Consensus

(Unassigned)

1.16.3, 1.16.4, 20w51a, 1.16.5, 1.18.1

Retrieved