Menu

#309 Preventing division by zero in src/ao.c

open
nobody
None
5
2025-07-30
2018-06-05
Jiri Kucera
No

Depending on system configuration, play <soundfile> sometimes ends with floating point exception. This bug is hard to reproduce. For me, it works only in mock sandbox.

SoX version: 14.4.2
OS: Fedora 27

Attachments: proposed patch

1 Attachments

Discussion

  • Jiri Kucera

    Jiri Kucera - 2018-06-05

    Sample audio file #1.

     
  • Jiri Kucera

    Jiri Kucera - 2018-06-05

    Sample audio file #2.

     
  • Jiri Kucera

    Jiri Kucera - 2018-06-05

    To the patch: In the original version of src/ao.c, I tried to figure out what the *= in

    ao->buf_size *= (ft->encoding.bits_per_sample >> 3);
    

    is for. Together with the previous line, the code snippet looks like well-known pattern for size alignment, so I replace *= for += (but maybe *= was there for some reason, it is hard to guess with no comments).

     
  • Jan Starý

    Jan Starý - 2023-02-13

    Is AO the default output on Fedora?
    If not, how ecatly do you send the output to AO?
    Does the FPE always occur when playing the above files via AO?
    Have you tried on other systems that use AO as their output?

     
  • Jan Starý

    Jan Starý - 2023-02-13

    I just tried on OpenBSD with only AO compiled in (--with-ao), --disabling all other outputs, including the native sndio. I can confirm that play segfaults on both of your examples.

    $ play -V6 sox-fpe.voc  
    play DBUG sox: Looking for a default device: trying format `ao'
    Floating point exception (core dumped) 
    
    #0  0x00000b33b5565459 in startwrite (ft=0x7f7ffffcfa20) at ao.c:38
    38        ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % (ft->encodin
    g.bits_per_sample >> 3));
    (gdb) bt
    #0  0x00000b33b5565459 in startwrite (ft=0x7f7ffffcfa20) at ao.c:38
    #1  0x00000b31a6ca11a3 in try_device (name=0xb31a6c97228 "ao") at sox.c:2525
    #2  0x00000b31a6c9ffcd in set_default_device (f=0x7f7ffffcff00) at sox.c:2547
    #3  0x00000b31a6c9af12 in main (argc=Variable "argc" is not available.
    ) at sox.c:2659
    
    $ play -V6 /home/hans/sox-fpe.wav  
    play DBUG sox: Looking for a default device: trying format `ao'
    Floating point exception (core dumped) 
    
    #0  0x0000074dda00c459 in startwrite (ft=0x7f7fffff64b0) at ao.c:38
    38        ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % (ft->encodin
    g.bits_per_sample >> 3));
    (gdb) bt
    #0  0x0000074dda00c459 in startwrite (ft=0x7f7fffff64b0) at ao.c:38
    #1  0x0000074bd8c371a3 in try_device (name=0x74bd8c2d228 "ao") at sox.c:2525
    #2  0x0000074bd8c35fcd in set_default_device (f=0x7f7fffff6990) at sox.c:2547
    #3  0x0000074bd8c30f12 in main (argc=Variable "argc" is not available.
    ) at sox.c:2659
    
     
  • Jan Starý

    Jan Starý - 2023-02-13

    I don't understand the buf_size dance either. In commit 3d4cdf3d163b9d8c6a4241ff412b785178af4865 it was changed from

    ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % ft->signal.size);
    ao->buf_size *= ft->signal.size;
    

    to

    ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % (ft->encoding.bits_per_sample >> 3));
    ao->buf_size *= (ft->encoding.bits_per_sample >> 3);
    

    Apparently, something like what the first line does needs to be there, because with a simple

    ao->buf_size = sox_globals.bufsiz;
    

    this is what happens:

    $ play -V6 /home/hans/sox-fpe.wav  
    play DBUG sox: Looking for a default device: trying format `ao'
    play FAIL ao: Could not open device: error 5
    play FAIL sox: Sorry, there is no default audio device configured
    

    i.e. it will compile and then simply not have the device, without any kind of error message.
    That is to say: with a buffer size being something else then what AO expects, we don't even have the device.

    The >> 3 is easy: a fancy division by eight, which might not work as intended, e,g, for signed;
    The bits_per_sample is defined in sox.h as follows:

     unsigned bits_per_sample;/**< 0 if unknown or variable; uncompressed value if lossless; compressed value if lossy */
    

    Surely an unsigned int won't be < 0, but even such basics are unclear.

    As an example, if bits_per_sample is 16, which is typical, then 16 >> 3 is 2 (i.e. two bytes hold the 16 bits),
    so sox_globals.bufsiz % (ft->encoding.bits_per_sample >> 3) is sox_globals.bufsiz % 2,
    so ao->buf_size = sox_globals.bufsiz - 0 or ... - 1; I have no idea what it is supposed to do,
    but that is the line that causes the SIGFPE (says gdb).

     
  • Jan Starý

    Jan Starý - 2023-02-13

    Also, using AO as an output makes play crash with a SIGFPE on any file whatsoever,
    not just on those example files.

    Which makes me believe that
    1. AO support is broken
    2. Nobody's been using it for a long time

    Are there any systrems that use AO as their default/native sound playing system?

     
  • Jan Starý

    Jan Starý - 2023-02-13

    After adding a few naive printfs: with any audio file whatsoever,
    the ft->encoding.bits_per_sample in these lines is zero.
    Setting the buf_size is just where it shows.

     

Log in to post a comment.

MongoDB Logo MongoDB