2

I am running a Windows program through Wine (i.e., wine example.exe). The program (or, more likely, Wine) has the funny behavior that instead of cleanly exiting when I close the application, it throws a read access exception; my terminal reads:

wine: Unhandled page fault on read access to 0x00000018 at address 0x7f7969ea (thread 0009), starting debugger...

As a result, the program doesn't exit cleanly and I have to Control-C in the terminal or kill -9 it to close the program.

Question: Is there a way to have the wine process exit whenever there is an unhandled page fault, instead of starting the debugger as the terminal output suggests? (An aside: the debugger doesn't actually start; there is a subsequent message complaining about errors starting the wine debugger.)

2
  • As an idea, the dirty way to do so: one could wrap wine and grep it's stdout stream for '0x00000018' (bad reference) pointer or a cleaner way with winedbg. – chzzh Jul 16 '20 at 8:53
  • Related bug: bugs.winehq.org/show_bug.cgi?id=49556 – kenorb Jul 17 '20 at 20:51
1

This python script implements the workaround suggested by @chzzh in the comments. Basically, it reads the stderr of the wine process and forcibly kills it when it finds a specified string, e.g., when it finds the string starting debugger... in stderr.

Here is how to use it: save the script below as watcher.py (any name works). Then

python3 ./watcher.py 'starting debugger...' wine <arguments and exe path for wine>

I've tested this and it works well for me.

Here is the script:

#!/bin/python3
import sys
import io
import select
from subprocess import Popen, PIPE, DEVNULL, STDOUT
from sys import argv

def kill_when_found(process, needle, size = io.DEFAULT_BUFFER_SIZE):
    if isinstance(needle, str):
        needle = needle.encode()
    assert isinstance(needle, bytes)

    stream = process.stderr
    assert stream is not None

    poll = select.poll()
    poll.register(stream, select.POLLIN)

    output_buffer = b''
    while process.poll() is None:
        result = poll.poll(100)
        if not result:
            continue

        output = stream.read1(size)
        sys.stdout.buffer.write(output)
        output_buffer += output
        if needle in output_buffer:
            process.kill()
            return process.poll()

        if len(output_buffer) >= len(needle):
            output_buffer = output_buffer[-len(needle):]

    return process.poll()

if __name__ == '__main__':
    if len(argv) <= 3:
        print("""
Usage: Pass in at least 2 arguments, the first argument is the search
string;
the remaining arguments form the command to be executed (and watched over).
""")
        sys.exit(0)
    else:
        process = Popen(argv[2:], stderr = PIPE)
        retcode = kill_when_found(process, argv[1])
        sys.exit(retcode)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.