python-sounddevice icon indicating copy to clipboard operation
python-sounddevice copied to clipboard

Segmentation fault (core dumped) on Alpine Linux

Open pvizeli opened this issue 7 years ago • 15 comments

I can't make that running with Alpine Linux.

Here is the dockerfile to reproduce it:

FROM alpine:3.6

# Setup base
RUN apk add --no-cache jq bash portaudio \
        python3 python3-dev \
        gcc libgcc \
        musl-dev musl \
        libffi-dev libffi \
    && pip3 install --no-cache --upgrade setuptools \
    && pip3 install --no-cache --upgrade sounddevice

CMD ["python3", "-m", "sounddevice"]

pvizeli avatar Jul 07 '17 09:07 pvizeli

What's "that"?

mgeier avatar Jul 07 '17 12:07 mgeier

That is a docker that make a development environment that can run python3 -m sounddevice.

I was not able to locate it but I think it can help to have a docker env for run the debuger. It should be easy as to setup a device with alpine linux to debug it.

pvizeli avatar Jul 09 '17 22:07 pvizeli

@pvizeli

It would be helpful if you could at least provide a log of what errors you're getting and possibly a hosted docker file for us to test with. Help us help you...

tgarc avatar Jul 18 '17 04:07 tgarc

@pvizeli Any more information? Any news?

mgeier avatar Oct 21 '17 08:10 mgeier

I'm closing this due to lack of response. Feel free to re-open with more information.

mgeier avatar Dec 06 '17 09:12 mgeier

This sadly is still an issue.

To reproduce using docker here's everything you need:

# $ cat Dockerfile
FROM alpine:3.11

RUN apk add --no-cache \
    python3 \
    python3-dev \
    gcc \
    musl-dev \
    libffi-dev \
    portaudio-dev

RUN python3 -m pip install sounddevice

Next build the image:

docker build -t sounddevice .

Finally execute it:

docker run -it sounddevice /bin/sh

This will give you a shell in which you run:

python3 -c 'import sounddevice'

If you need anything else, please let me know

tadly avatar Jan 19 '20 12:01 tadly

Thanks for the update.

If you need anything else, please let me know

It would probably be helpful to know where exactly the segmentation fault happens (that information should be in the core file).

It might be interesting to know whether other versions of PortAudio work.

It might be interesting to know whether other modules using PortAudio (e.g. PyAudio) work.

It might also be interesting to know whether other modules using CFFI (e.g. soundfile) work.

If the segfault happens during import sounddevice, the problem is most likely in the function _initialize(). You could randomly un-comment a few lines to further isolate the cause of the error. The line with Pa_Initialize and the line with fopen (plus the following line) would be good candidates.

mgeier avatar Jan 20 '20 10:01 mgeier

Edit: This was not meant to sound rude but kinda does. Sorry

Sorry but I don't really have time to fully debug the issue (I'd have done so if I had)

I however managed to get a core dump which I've attached.

Here are the steps necessary to produce one yourself if necessary... First create the image as outline before, then:

$ docker run --device=/dev/snd:/dev/snd -v '/tmp/sounddevice:/data' --privileged -it sounddevice /bin/sh
$ echo '/data/core' > /proc/sys/kernel/core_pattern
$ python3 -c 'import sounddevice'

After that a core dump is located in the hosts /tmp/sounddevice directory

Commenting stuff within _initialize I found that setattr(stdio, stderr_name, devnull) is causing the first segfault. Another one follows soon after though.

The attached core-dump is without any modifications

core.zip

tadly avatar Jan 20 '20 12:01 tadly

Edit: This was not meant to sound rude but kinda does. Sorry

Don't worry, I didn't perceive any of this as rude.

Sorry but I don't really have time to fully debug the issue (I'd have done so if I had)

No problem. It's totally OK to report an issue and not having the time to fix it.

As long as you don't expect me to have the time to do it.

I however managed to get a core dump which I've attached.

Thanks, but I think I can only get meaningful information out if I have the corresponding executable. Anyway, I don't really know how to diagnose these kinds of problems ...

Commenting stuff within _initialize I found that setattr(stdio, stderr_name, devnull) is causing the first segfault. Another one follows soon after though.

OK, cool, that's probably helpful.

We could create a minimal example that only contains the necessary code to generate the segfault. This would not need the full sounddevice module and not even the PortAudio library.

We could then ask the CFFI people what could be the problem, they are normally very helpful and I'm sure they know how to diagnose such a thing.

mgeier avatar Jan 24 '20 17:01 mgeier

Hello I'm facing the similar issue on alpine linux i try to build docker image for the LedFx project when i try to import sounddevice module i get this error

bash-5.1$ python
Python 3.9.6 (default, Jun 29 2021, 19:45:46) 
[GCC 10.2.1 20201203] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sounddevice
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/LedFx/venv/lib/python3.9/site-packages/sounddevice.py", line 71, in <module>
    raise OSError('PortAudio library not found')
OSError: PortAudio library not found
>>>

i have alse and portaudio lib installed

bash-5.1$ ldd /usr/lib/libportaudi*
        /lib/ld-musl-x86_64.so.1 (0x7f1f3c5ea000)
        libasound.so.2 => /usr/lib/libasound.so.2 (0x7f1f3c4f8000)
        libjack.so.0 => /usr/lib/libjack.so.0 (0x7f1f3c4bc000)
        libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f1f3c5ea000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x7f1f3c31a000)
        libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x7f1f3c300000)
bash-5.1# find . -name libportaudi* 
./usr/lib/libportaudio.so.2
./usr/lib/libportaudio.so.2.0.0
./usr/lib/libportaudiocpp.so
./usr/lib/libportaudiocpp.so.0
./usr/lib/libportaudio.so
./usr/lib/libportaudiocpp.so.0.0.12
bash-5.1# ls -l /usr/lib/libportaudio*
lrwxrwxrwx    1 root     root            21 Aug 11 07:26 /usr/lib/libportaudio.so -> libportaudio.so.2.0.0
lrwxrwxrwx    1 root     root            21 Aug 11 07:26 /usr/lib/libportaudio.so.2 -> libportaudio.so.2.0.0
-rwxr-xr-x    1 root     root        171176 Sep 18  2019 /usr/lib/libportaudio.so.2.0.0
lrwxrwxrwx    1 root     root            25 Aug 11 07:26 /usr/lib/libportaudiocpp.so -> libportaudiocpp.so.0.0.12
lrwxrwxrwx    1 root     root            25 Aug 11 07:26 /usr/lib/libportaudiocpp.so.0 -> libportaudiocpp.so.0.0.12
-rwxr-xr-x    1 root     root         55184 Sep 18  2019 /usr/lib/libportaudiocpp.so.0.0.12

spiro-c avatar Aug 11 '21 08:08 spiro-c

@spiro-c This is a different issue (no segmentation fault).

It looks like ctypes.util.find_library('portaudio') doesn't find the library.

mgeier avatar Aug 11 '21 18:08 mgeier

right, you need a patched python executable for alpine that includes some patches from the alpine repository. The vanilla python will not work. You can use our https://github.com/home-assistant/docker-base

pvizeli avatar Aug 12 '21 08:08 pvizeli

Sorry for pinging to old issue. I have the similar segmentation fault on alpine, so I'm interested in this.

While googling about 'alpine segmentation fault', I found many issues on other repositories. And it seems like some of them was because of musl that is used as standard c library on alpine. (e.g. https://github.com/lovell/sharp/issues/2570)

So I run alpine image with build-base package installed:

$ sudo docker pull alpine
$ sudo docker run -ti alpine /bin/sh
# # inside alpine
$ apk add build-base
$ find / -name 'stdio.h'
/usr/include/stdio.h
/usr/include/fortify/stdio.h
/usr/include/c++/11.2.1/tr1/stdio.h

Read /usr/include/stdio.h, and I found that stderr is defined as FILE *const stderr (on git.musl-libc.org):

...
extern FILE *const stderr;
...
#define stderr (stderr)
...

whereas in GNU C library on my archlinux it is defined as FILE *stderr (on sourceware.org):

...
extern FILE *stderr;            /* Standard error output stream.  */
...
#define stderr stderr

And sounddevice_build.py of this library have comment about GNU C library definition, but not about musl. https://github.com/spatialaudio/python-sounddevice/blob/80d8930ea3cca16537df99ba57ad3692ebd90356/sounddevice_build.py#L314-L320

I'm totally newbie to C and doesn't know how things are working around there, but I thought those differences might be the problem. Sorry if it's already considered. Hope it helps. Thanks

Cj-bc avatar Jul 04 '22 07:07 Cj-bc

As a quick workaround, It seems like removing forwarding stderr codes makes it work. It's not tested and all logs will be displayed to normal stderr(e.g. terminal), but here's my workaround code.

https://github.com/Cj-bc/python-sounddevice/tree/workaround/i90/remove-stderr-fowarding

Cj-bc avatar Jul 04 '22 08:07 Cj-bc

I wrote some code and (almost) confirmed that changing stderr causes segmentation fault.

Full code and documentation are at Cj-bc/alpine-stderr-changing-test. I wrote C version, and it worked. So it's possible to change stderr to /dev/null in C, but I couldn't find any way to do it in python.

would you mind to review this, @mgeier? Note that this isn't problem for me now, so I don't need fast reaction. If there's something unclear, let me know.

Thanks.

Docker environment that I tested

FROM python:3.9-alpine

WORKDIR workdir
RUN pip install cffi
COPY _ffi_test.py requirements.txt ./
RUN pip install -r requirements.txt && python _ffi_test.py
COPY stderr-changing.py ./
CMD python stderr-changing.py

Minimum code to reproduce segmentation fault

Minimum ffi definition is:

from cffi import FFI

ffibuilder = FFI()

ffibuilder.set_source("_ffi_test", None)
ffibuilder.cdef("""
    FILE* fopen(const char* path, const char* mode);
    extern FILE* stderr;
""")

if __name__ == '__main__':
    ffibuilder.compile(verbose=True)

executable is:

from _ffi_test import ffi as _ffi
import os as _os

stdio = _ffi.dlopen(None)
getattr(stdio, 'stderr')
devnull = stdio.fopen(_os.devnull.encode(), b'w')
setattr(stdio, 'stderr', devnull)

What is problem?

My opinion is same as my previous comment, I think difference between GNU C library and musl is the problem.

I tried to use musl's stderr definition in ffi, but it gives me error in some way.(Details are in README of my test code repo) As far as I tried, I think it's impossible to change stderr to /dev/null in python.

Cj-bc avatar Jul 13 '22 03:07 Cj-bc

Thanks @Cj-bc for the detailed informations, that's very interesting!

I found this link, suggesting to use freopen(): https://wiki.gentoo.org/wiki/Musl_porting_notes#error:assignment_of_read-only_variable.27.5Bstdout.7Cstdin.7Cstderr.5D.27

I think this might work for redirecting, but I didn't find a way to restore the original stderr after the redirection.

Then I found https://stackoverflow.com/questions/7664788/freopen-stdout-and-console and https://stackoverflow.com/questions/1908687/how-to-redirect-the-output-back-to-the-screen-after-freopenout-txt-a-stdo, where some of the answers suggest using dup2().

I created #444 for trying this, but I have the feeling that this might not work on Alpine either ...

mgeier avatar Nov 17 '22 19:11 mgeier

I've tried #444 with Docker, and it seems to work, it doesn't segfault!

Can somebody please confirm?

I haven't tried if it still works on Windows.

mgeier avatar Nov 18 '22 17:11 mgeier