Sfml: Playing certain ogg files cause crashes in 2.4.2 that did not in 2.1

Created on 13 Jun 2017  路  9Comments  路  Source: SFML/SFML

Hello,

I am updating an application that uses sfml-audio from 2.1 to 2.4.2 that consistently crashes when playing certain ogg files. These files did not crash in 2.1, and its worth noting that they only crash when loading from stream, but if they are loaded from file they play fine.

Here is an example of an overridden InputStream class that suffers this issue:

#include <SFML/Audio.hpp>
#include <SFML/System.hpp>

class MyStream: public sf::InputStream
{
public:
   MyStream(std::string const& uri);
   sf::Int64 read(void* data, sf::Int64 size) override;
   sf::Int64 seek(sf::Int64 position) override;
   sf::Int64 tell() override;
   sf::Int64 getSize() override;

private:
   std::shared_ptr<std::istream> _stream;
   sf::Int64 _size;
};

MyStream::MyStream(std::string const& path)
{
   std::shared_ptr<std::ifstream> in = std::make_shared<std::ifstream>(path, std::ios::in | std::ios::binary);
   _stream = std::static_pointer_cast<std::istream>(in);
   _stream->seekg(0, std::ios_base::end);
   _size = tell();
   _stream->seekg(0, std::ios_base::beg);
}

sf::Int64 MyStream::read(void* data, sf::Int64 size)
{
   _stream->read((char *)data, size);
   return _stream->gcount();
}

sf::Int64 MyStream::seek(sf::Int64 position)
{
   _stream->seekg(position, std::ios_base::beg);
   return tell();
}

sf::Int64 MyStream::tell()
{
   return _stream->tellg();
}

sf::Int64 MyStream::getSize()
{
   return _size;
}

I believe I am following the guidelines listed here: https://www.sfml-dev.org/tutorials/2.4/system-stream.php

Here is the problematic ogg file. This file passes the oggz validate program.

I should note that I have tried the above changing the implementation slightly - using raw pointers, using a raw filebuf, etc., but all modifications suffer from the same issue. If I set the istreams exceptions and wrap each call in a try/catch, it seems that read fails due to the eof bit being set.

An additional peculiar thing to note is that if I open the problematic file in audacity and save it with varying levels of compression I get different results. Here is the file and its results for each 10 quality levels Audacity allows me to export the file to:

0 quality - program runs, no audio plays
1 quality - same as above
2 quality - program crashes
3 quality - program hangs forever
4 quality - no audio plays
5 quality - program works, audio plays
6 quality - crashes
7 quality - crashes
8 quality - program works, audio plays
9 quality - program works, audio plays
10 quality - program works, audio plays

I know that since 2.1 SFML has removed libsndfile - is it possible that my problem is related to this?

Any help is greatly appreciated!

bug sfml-audio rejected

Most helpful comment

OK so I've looked at this. Here's a minimal testcase which crashes: https://gist.github.com/jcowgill/4fa0b227e1575e4baec82833a63d1bfa

I've adjusted the testcase to remove the shared_ptr objects to simplify things a bit.

There are 2 bugs here:

  • Your implementation of sf::InputStream::seek is wrong in the case where you attempt to seek after the entire file has been read (which is required by the OGG reader). If you read from an istream past the end of a file, the failbit is set. This will later cause all calls to tellg to return -1 instead of the actual position. You can probably fix this by adding _stream.clear() at the start of MyStream::seek.
  • There appears to be a bug in vorbisfile where if seek fails at a specific time when a file is loaded, it will attempt to free some uninitialized memory and crash. The relevant part is in https://git.xiph.org/?p=vorbis.git;a=blob;f=lib/vorbisfile.c#l1232 (the ov_raw_seek function). If seek_helper on line 1257 (which calls your seek function) fails, then work_os will be freed on 1396 without having been initialized.

All 9 comments

We'll need a truly complete, and minimal, program that reproduce the issue. Also, check what happens with the master version. Further details on how to report bugs are explained in the contribution guidelines. And what happens if you read the ogg file with sf::Music directly? If the bug is present with the master version, check if SFML dependencies can be updated and if it fixes the bug.

OK so I've looked at this. Here's a minimal testcase which crashes: https://gist.github.com/jcowgill/4fa0b227e1575e4baec82833a63d1bfa

I've adjusted the testcase to remove the shared_ptr objects to simplify things a bit.

There are 2 bugs here:

  • Your implementation of sf::InputStream::seek is wrong in the case where you attempt to seek after the entire file has been read (which is required by the OGG reader). If you read from an istream past the end of a file, the failbit is set. This will later cause all calls to tellg to return -1 instead of the actual position. You can probably fix this by adding _stream.clear() at the start of MyStream::seek.
  • There appears to be a bug in vorbisfile where if seek fails at a specific time when a file is loaded, it will attempt to free some uninitialized memory and crash. The relevant part is in https://git.xiph.org/?p=vorbis.git;a=blob;f=lib/vorbisfile.c#l1232 (the ov_raw_seek function). If seek_helper on line 1257 (which calls your seek function) fails, then work_os will be freed on 1396 without having been initialized.

And here's my vorbis bug for reference: https://trac.xiph.org/ticket/2327

Thank you!

Are there any docs on updating sfml's dependencies so I can see if this would remedy my problem? I've tried downloading libogg and libvorbis, applying the patch @jcowgill made, then I built libogg_static.lib, libvorbis_static.lib, and libvorbisfile_static.lib, moved those to the appropriate extlibs directories in SFML, renamed them to match the naming that SFML uses, then built the project, but now I am not hearing any sound. I'm unsure if I have just set something up incorrectly, or if I have built the dependencies wrong, or if something else is going on.

You will have not sound, because your InputStream::seek is wrong. Read jcowgill commend.
Now orbis will not break in error stream. But you have not repair your problem.

@1aam2am1 I have added in the clear call within seek as suggested. Additionally - we previous had ogg files that would play. Now none of them play. With/without this suggestion no sound plays at all.

I'm not sure if I can help you much here. Adding the call to clear like this (and without changing libvorbisfile), allows you example ogg to play properly for me:

sf::Int64 MyStream::seek(sf::Int64 position)
{
    _stream.clear();
    _stream.seekg(position, std::ios_base::beg);
    return tell();
}

I'm using Debian 9 x86_64. I haven't tried windows.

The culprit is read which can set eof/failbit on your stream when reaching EOF. @jcowgill's solution works fine here. 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

FQLT picture FQLT  路  9Comments

JonesBlunt picture JonesBlunt  路  7Comments

shayanaminnjad picture shayanaminnjad  路  8Comments

sevagh picture sevagh  路  8Comments

fxcoudert picture fxcoudert  路  7Comments