SFML / SFML.Net

Official binding of SFML for .Net languages

Home Page:https://www.sfml-dev.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash On Disposing Music

Rosst0pher opened this issue · comments

commented

When an instance of Music created from a Stream is disposed, the application crashes without any exception raised.

In the example, Dispose method crashes the application and closes with exit code -1073740791 (0xc0000409)

static void Main(string[] args)
{
    using var file = File.OpenRead("tune.ogg");
    var music = new Music(file);
    music.Play();

    Console.Read();

    music.Stop();
    music.Dispose();

    Console.WriteLine("end");
}

The crash actually occurs in CSFML during the call to Music.sfMusic_destroy(this.CPointer), which is why the debugger doesn't spring into action.

My guess is, that there's something odd going on with the destruction of the stream. I tried to reproduce it with CSFML, but am a bit stuck on the custom sfInputStream struct and connecting an actual stream to it.
Here's my current code, but it gets stuck in the FLAC reader, trying to read the meta data.

#include <SFML/Audio.h>
#include <fstream>

sfInt64 read(void* data, sfInt64 size, void* userData)
{
    return static_cast<std::ifstream*>(userData)->readsome(static_cast<char*>(data), size);
}

sfInt64 seek(sfInt64 position, void* userData)
{
    static_cast<std::ifstream*>(userData)->seekg(position);
    return static_cast<std::ifstream*>(userData)->tellg();
}

sfInt64 tell(void* userData)
{
    return static_cast<std::ifstream*>(userData)->tellg();
}

sfInt64 getSize(void* userData)
{
    auto stream = static_cast<std::ifstream*>(userData);
    const auto position = stream->tellg();
    stream->seekg(0, std::ios::end);
    const auto size = stream->tellg() - position;
    stream->clear();
    stream->seekg(position);
    return size;
}

int main()
{
    std::ifstream real_stream;
    real_stream.open("orchestral.ogg", std::ios::in | std::ios::binary);

    sfInputStream input_stream;
    input_stream.read = &read;
    input_stream.seek = &seek;
    input_stream.tell = &tell;
    input_stream.getSize = &getSize;
    input_stream.userData = &real_stream;

    auto music = sfMusic_createFromStream(&input_stream);
    sfMusic_destroy(music);
}

This happens to me sometimes, but it can also crash playing in the middle occasionally (using CSFML). Not sure if this is related or could be a different bug.

Here is a link to a WAV (hand made in code) that plays perfectly most of the time (100% of the time in Audacity and other sound players/editors), but when loaded with sfMusic_createFromMemory will sometimes suffer from one of the following:

  • Play distorted at about the 1/2 way mark; will continue distorted until it crashes if told to loop.
  • Crashes when being destroyed with sfMusic_destroy (after being stopped).

https://www.dropbox.com/s/tcigc9o5fikdxnh/call-to-post.wav?dl=0

Here is another very short WAV (again, just hand made) that plays and loops perfectly with other tools that - with CSFML (loadFromMemory) will quickly distort after 1 or 2 loops and eventually lead to a crash.

https://www.dropbox.com/s/pjrz441ukrm5b82/short.wav?dl=0

Hopefully these can help track down the issue?

Edit: I just noticed this was the SFML.Net repo (I got here via a Google search). If you'd like me to move this to the CSFML repo, please let me know. Otherwise I'll assume this is useful here. 😄

commented

Had another look over this today as it showed up again. The exit code is STATUS_STACK_BUFFER_OVERRUN which sounds fun...

I did notice the struct mapping of InputStream on SFML.Net side is missing userData field but after testing it doesn't seem related. I have tested adding a userData field on .NET side so the structs are both the same but it doesn't fix this specific issue which makes me wonder If I've just found another bug, maybe.

https://github.com/SFML/CSFML/blob/master/include/SFML/System/InputStream.h#L44

https://github.com/SFML/SFML.Net/blob/master/src/SFML.System/StreamAdaptor.cs#L14

While SFML.Net doesn't use the userData field, from what I could find CSFML doesn't dereference the userData pointer and just passes it through which might explain why this might not have been noticed. Also the P/Invoke method signature passes InputStream by pointer so that wouldn't have complained about a mismatch either.

I'd imagine if CSFML did dereference the userData field in this circumstance you'd probably get a access violation.

commented

I retested this bug on latest CSFML branch and its fixed by SFML/CSFML#163

This is now just waiting for a new release of CSFML to include the fix.

Thanks for retesting this, I'll close this issue then. 🙂