cdrom
cdrom

Reputation: 599

Subprocess, stderr to DEVNULL but errors are printed

I am working on a French chatbot using python. For a first text-to-speech attempt, I am using espeak with mbrola. I call it with subprocess :

from subprocess import run, DEVNULL

def speak(text):
    command = ["espeak", "-vmb-fr1", text]
    run(command, stderr=DEVNULL, stdout=DEVNULL)

speak("Bonjour.")

As you see, I'm sending stderr and stdout to /dev/null

When I run the program, It seems to work, espeak is speaking, but I get this :

*** Error in `mbrola': free(): invalid pointer: 0x08e3af18 ***
*** Error in `mbrola': free(): invalid pointer: 0x0988af88 ***

I think it is a C error in mbrola. I think I can't fix it. But it works, so I just want to mute the error. How can I do ? Is there a way ?


Edit, in response to abarnert :

When I redirect stdout and stderr by the shell (python myscript.py 2>&1 >/dev/null), the message still show up.

Upvotes: 3

Views: 1526

Answers (2)

abarnert
abarnert

Reputation: 365975

The root problem is that mbrola/espeak has a serious bug with memory allocation. If you haven't checked for a new version, and reported the bug to them, that's the first thing you should do.

These warnings are emitted by glibc's malloc checker, which is described in the mallopt docs. If heap checking is enabled, every detected error with malloc (and free and related functions) will be printed out to stderr, but if it's disabled, nothing will be done. (Other possibilities are available as well, but that's not relevant here.)

According to the documentation, unless the program explicitly calls mallopt, either setting the environment variable MALLOC_CHECK_ to 0 or not setting it at all should mean no malloc debug output. However, most of the major distros (starting with Debian) have long shipped a glibc that's configured to default to 1 (meaning print the error message) instead of 0. You can still override this by explicitly setting MALLOC_CHECK_=0.

Also, the documentation implies that malloc errors go to stderr unless malloc_printerr is replaced. But again, many distros do replace it with an intentionally-harder-to-ignore function that logs to the current process's tty if pretend and stderr if not. This is why it shows up even if you pipe espeak's stderr to /dev/null, and your own program's as well.

So, to hide these errors, you can:

  • Set the environment variable MALLOC_CHECK_ to 0 in espeak, which will disable the checks.
  • Prevent espeak from opening a tty, which means the checks will still happen, but the output will have nowhere to go.

Using setsid, a tool that calls setsid at the start of the new process, is one way to do the latter. Whether that's a good idea or not depends on whether you want the process to lead its own process group. You really should read up on what that means and decide what you want, not choose between the options because typing setsid is shorter than typing MALLOC_CHECK_=0.

And again, you really should check for a new version first, and report this bug upstream if they haven't fixed it yet.

Upvotes: 1

Davis Herring
Davis Herring

Reputation: 40013

Run it with setsid (just add that string in front of the command and arguments). That will stop it from opening /dev/tty to report the malloc errors. It will also prevent terminal signals, including SIGHUP when the terminal is closed, from affecting the process, which may be a good or a bad thing.

Alternatively, set the environment variable LIBC_FATAL_STDERR_ to some nonempty string, with whose name I was able to find several similar questions.

Upvotes: 2

Related Questions