appsrc: Spurious wakeup of gst_app_src_create can trigger a need_data callback after a response buffer has been pushed.
In gst_app_src_create, for a GstAppSrc in random-access mode, there is a mechanism by which buffers pushed after the need-data callback has returned are supported. Namely, after need_data is returned, if the buffer queue is still empty, the internal conditional variable will be waited upon before checking again for a buffer. However, not only the pushing of a buffer can trigger this conditional variable, at least gst_app_src_set_caps also appears to trigger this conditional variable. In any case, after this wakeup, GstAppSrc sees that there has still been no buffers pushed to the queue, so it calls need-data again. The problem is, before it calls need-data, it unlocks the mutex, and this is where a race occurs. In the bad case, if a the unlocked mutex first wakes allows a push-buffer call to finish, then afterwards need-data is actually run, need-data will have no easy way to differentiate this call from a the GstAppSrc requesting a new buffer directly following the previous one.
At this point the possible buggy paths can go in a variety of directions, but one example would be that the GstAppSrc gets another getrange/create call with the same size but at a different offset. While the client code is asynchronously reading a response to what it thinks is the next request (I'll call it the ghost request), seek-data will be called for the actual next request, setting the offset for the next read, but at this point it will already have been too late as the client code pushes the ghost request's response buffer of the same size and it is treated as the post-seek buffer.
There are multiple steps along this path where the problem could be prevented, but since I'm not the designer I'm not sure which would be considered most correct. One could check upon a wakeup whether the wakeup is due to a buffer push, one could verify the buffer's offset field and discard it if it doesn't match, one could retain the mutex on a need_data callback, changing the API contract.
To work around this, after acquiring our own mutex in our need_data callback, we are going to check the current-level-buffers property to determine whether the need-data call was spurious or not.