GNOME Bugzilla – Bug 582942
crash in libvorbis when parsing some ogg files
Last modified: 2009-08-10 23:29:46 UTC
While running the Mirage plugin in Banshee to rescan the music directory a crash occurs in libvorbis. Looking at the backtrace it seems that gst-plugins-vorbis is passing a badly initialised structure.
The backtrace for the crash is thus: (gdb) bt
+ Trace 215530
Stack level 3, frame at 0x428e4c80: rip = 0x2aaabfd4720d in vorbis_dec_chain (vorbisdec.c:1368); saved rip 0x2aaab983c276 called by frame at 0x428e4cd0, caller of frame at 0x428e4bd0 source language c. Arglist at 0x428e4bc8, args: pad=<value optimized out>, buffer=0x2aaab12c9400 Locals at 0x428e4bc8, Previous frame's sp is 0x428e4c80 Saved registers: rbx at 0x428e4c48, rbp at 0x428e4c50, r12 at 0x428e4c58, r13 at 0x428e4c60, r14 at 0x428e4c68, r15 at 0x428e4c70, rip at 0x428e4c78 (gdb) info locals vd = (GstVorbisDec *) 0x2aaab12fcb20 result = <value optimized out> discont = 0 __PRETTY_FUNCTION__ = "vorbis_dec_chain" (gdb) p *vd $11 = {element = {object = {object = {g_type_instance = {g_class = 0x2aaab12de690}, ref_count = 2, qdata = 0x0}, refcount = 0, lock = 0x2163ba0, name = 0x33891e0 "vorbisdec4", name_prefix = 0x0, parent = 0x0, flags = 0, _gst_reserved = 0x0}, state_lock = 0x33f08c0, state_cond = 0x33db550, state_cookie = 1, current_state = GST_STATE_PAUSED, next_state = GST_STATE_VOID_PENDING, pending_state = GST_STATE_VOID_PENDING, last_return = GST_STATE_CHANGE_SUCCESS, bus = 0x0, clock = 0x0, base_time = 0, numpads = 2, pads = 0x2aaab13708a0, numsrcpads = 1, srcpads = 0x2205fa0, numsinkpads = 1, sinkpads = 0x2aaab1350c20, pads_cookie = 2, abidata = {ABI = { target_state = GST_STATE_PAUSED}, _gst_reserved = {0x3, 0x0, 0x0, 0x0}}}, sinkpad = 0x2aaab12b7450, srcpad = 0x2aaab12fe730, vd = {analysisp = 0, vi = 0x0, pcm = 0x0, pcmret = 0x0, pcm_storage = 0, pcm_current = 0, pcm_returned = 0, preextrapolate = 0, eofflag = 0, lW = 0, W = 0, nW = 0, centerW = 0, granulepos = 0, sequence = 0, glue_bits = 0, time_bits = 0, floor_bits = 0, res_bits = 0, backend_state = 0x0}, vi = {version = 0, channels = 2, rate = 44100, bitrate_upper = 4294967295, bitrate_nominal = 112015, bitrate_lower = 4294967295, bitrate_window = 0, codec_setup = 0x3458b30}, vc = {user_comments = 0x2254cc0, comment_lengths = 0x33442e0, comments = 2, vendor = 0x33d3930 "Xiphophorus libVorbis I 20011231"}, vb = {pcm = 0x0, opb = {endbyte = 0, endbit = 0, buffer = 0x0, ptr = 0x0, storage = 0}, lW = 0, W = 0, nW = 0, pcmend = 0, mode = 0, eofflag = 0, granulepos = 0, sequence = 0, vd = 0x2aaab12fcc18, localstore = 0x0, localtop = 0, localalloc = 0, totaluse = 0, reap = 0x0, glue_bits = 0, time_bits = 0, floor_bits = 0, res_bits = 0, internal = 0x0}, granulepos = 18446744073709551615, initialized = 1, queued = 0x0, output = 0x0, gather = 0x0, decode = 0x0, segment = {rate = 1, abs_rate = 1, format = GST_FORMAT_TIME, flags = GST_SEEK_FLAG_NONE, start = 0, stop = -1, time = 0, accum = 0, last_stop = 0, duration = -1, applied_rate = 1, _gst_reserved = '\0' <repeats 23 times>}, discont = 1, seqnum = 486, cur_timestamp = 18446744073709551615, prev_timestamp = 18446744073709551615, pendingevents = 0x0, taglist = 0x0}
The versions of gstreamer installed are: danny ~ # equery l gst [ Searching for package 'gst' in all categories among: ] * installed packages [I--] [ ] dev-python/gst-python-0.10.12 (0.10) [I--] [ ~] media-libs/gst-plugins-bad-0.10.11 (0) [I--] [ ~] media-libs/gst-plugins-base-0.10.23 (0.10) [I--] [ ~] media-libs/gst-plugins-good-0.10.14 (0.10) [I--] [ ~] media-libs/gst-plugins-ugly-0.10.11 (0.10) [I--] [ ~] media-libs/gstreamer-0.10.23 (0.10) [I--] [ ] media-plugins/gst-plugins-a52dec-0.10.11 (0.10) [I--] [ ] media-plugins/gst-plugins-alsa-0.10.22 (0.10) [I--] [ ] media-plugins/gst-plugins-cdparanoia-0.10.22 (0.10) [I--] [ ] media-plugins/gst-plugins-dvdread-0.10.11 (0.10) [I--] [ ] media-plugins/gst-plugins-esd-0.10.14 (0.10) [I--] [ ] media-plugins/gst-plugins-faac-0.10.11 (0.10) [I--] [ ] media-plugins/gst-plugins-faad-0.10.11 (0.10) [I--] [ ] media-plugins/gst-plugins-ffmpeg-0.10.7 (0.10) [I--] [ ] media-plugins/gst-plugins-flac-0.10.14 (0.10) [I--] [ ] media-plugins/gst-plugins-gconf-0.10.14 (0.10) [I--] [ ] media-plugins/gst-plugins-gnomevfs-0.10.22 (0.10) [I--] [ ] media-plugins/gst-plugins-lame-0.10.11 (0.10) [I--] [ ] media-plugins/gst-plugins-mad-0.10.11 (0.10) [I--] [ ] media-plugins/gst-plugins-meta-0.10-r2 (0.10) [I--] [ ] media-plugins/gst-plugins-mpeg2dec-0.10.11 (0.10) [I--] [ ~] media-plugins/gst-plugins-ogg-0.10.23 (0.10) [I--] [ ] media-plugins/gst-plugins-pango-0.10.20 (0.10) [I--] [ ] media-plugins/gst-plugins-taglib-0.10.14 (0.10) [I--] [ ] media-plugins/gst-plugins-theora-0.10.22 (0.10) [I--] [ ] media-plugins/gst-plugins-v4l2-0.10.8 (0.10) [I--] [ ~] media-plugins/gst-plugins-vorbis-0.10.23 (0.10) [I--] [ ] media-plugins/gst-plugins-x-0.10.22 (0.10) [I--] [ ] media-plugins/gst-plugins-xvideo-0.10.22 (0.10)
Could make a sample file that triggers the crash available? Or the beginning of it? (head --bytes=500k foo.ogg > head.ogg)
Created attachment 134816 [details] First 500k of broken ogg file. Here is the first 500k of the file. How can I try and process it directly with gstreamer so I don't need to use banshee to re-create the crash?
> How can I try and process it directly with > gstreamer so I don't need to use banshee to re-create the crash? That depends a bit on what banshee uses internally. Usually something like this should do the trick: $ gst-launch-0.10 playbin2 uri=file:///path/to/foo.ogg $ gst-launch-0.10 playbin uri=file:///path/to/foo.ogg $ gst-launch-0.10 filesrc location=/path/to/foo.ogg ! decodebin2 ! audioconvert ! audioresample ! autoaudiosink
Confirmed, bug occurs with command line launch as well: 17:50 alex@danny/x86_64 [~] >gdb --args gst-launch-0.10 filesrc location=/home/alex/music/Mixture/Dee-lite\ -\ Groove\ Is\ In\ The\ Heart.ogg ! decodebin2 ! audioconvert ! audioresample ! autoaudiosink GNU gdb 6.8 Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-pc-linux-gnu"... (no debugging symbols found) (gdb) r Starting program: /usr/bin/gst-launch-0.10 filesrc location=/home/alex/music/Mixture/Dee-lite\ -\ Groove\ Is\ In\ The\ Heart.ogg \! decodebin2 \! audioconvert \! audioresample \! autoaudiosink (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) [Thread debugging using libthread_db enabled] [New Thread 0x7f4b315d66f0 (LWP 18711)] Setting pipeline to PAUSED ... [New Thread 0x41097950 (LWP 18715)] Pipeline is PREROLLING ... Program received signal SIGSEGV, Segmentation fault.
+ Trace 215534
Thread 1091139920 (LWP 18715)
Doesn't crash for me with git. This might only be because oggdemux goes into an endless loop when scanning the file though :)
oggdemux goes into an endless loop because the last page is truncated...
Shouldn't the demuxer handle corrupted pages gracefully though. If there is a guide on running git gstreamer alongside a system one please point me at it and I'll test on my rig with the latest git head.
This fixes the endless loop and makes this file play fine for me. Maybe the bug is only present in the complete file? Can you verify this? commit ed36eafabae42f73143bf3f6beaf58d793b28132 Author: Wim Taymans <wim.taymans@collabora.co.uk> Date: Tue May 19 12:45:59 2009 +0200 oggdemux: don't loop when at EOS When we try to read the last page, don't try to read past the upper boundary, as this might cause endless loops. See #582942
I'll see if I can patch the system gstreamer, unless there is a pointer to running a parallel gstreamer.
> I'll see if I can patch the system gstreamer, unless there is a pointer to > running a parallel gstreamer. There is, see: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/faq/html/chapter-developing.html#developing-uninstalled-gstreamer You'll need to checkout both gstreamer core and gst-plugins-base then.
Afraid it's not the bug that hit me: Starting program: /home/alex/src/gstreamer/gstreamer.git/tools/.libs/lt-gst-launch-0.10 filesrc location=/home/alex/broken.ogg \! decodebin2 \! audioconvert \! audioresample \! autoaudiosink [Thread debugging using libthread_db enabled] [New Thread 0x7f2d807a86f0 (LWP 23604)] Setting pipeline to PAUSED ... [New Thread 0x4094b950 (LWP 23608)] Pipeline is PREROLLING ... Program received signal SIGSEGV, Segmentation fault.
+ Trace 215603
Thread 1083488592 (LWP 23608)
$2 = (vorbis_info *) 0x0 (gdb)
Does it crash for you with the truncated file too?
Created attachment 135003 [details] [review] Current debugging patch Throwing in some fprintf's I see this: Starting program: /home/alex/src/gstreamer/gstreamer.git/tools/.libs/lt-gst-launch-0.10 filesrc location=/home/alex/broken.ogg \! decodebin2 \! audioconvert \! audioresample \! autoaudiosink [Thread debugging using libthread_db enabled] [New Thread 0x7f811bad76f0 (LWP 24880)] Setting pipeline to PAUSED ... [New Thread 0x42604950 (LWP 24882)] Pipeline is PREROLLING ... vorbis_dec_change_state: 0x10dce20, 0xa NULL to READY default case 2: 0xa vorbis_dec_change_state: 0x10dce20, 0x13 READY to PAUSED default case 2: 0x13 vorbis_dec_chain: vd=0x10dce20 vorbis_dec_chain: vd=0x10dce20 vorbis_dec_chain: vd=0x10dce20 vorbis_dec_chain: vd=0x10dce20 Program received signal SIGSEGV, Segmentation fault.
+ Trace 215616
Thread 1113606480 (LWP 24882)
AFAICT the vorbis_dec_change_state never calls vorbis_info_init but as I'm not familiar with the architecture of gstreamer I have no idea if this is a good or bad thing.
Comment on attachment 135003 [details] [review] Current debugging patch Ignore that, the structure is initialised. However vd in the crashing case is a new vd
Well in my case vorbis_synthesis_init is failing and therefore vorbis cannot continue until it is correctly initialised. I don't think this is a guaranteed success operation so shouldn't GStreamer pay attention to the return values? diff --git a/ext/vorbis/vorbisdec.c b/ext/vorbis/vorbisdec.c index 6b3f725..a890f66 100644 --- a/ext/vorbis/vorbisdec.c +++ b/ext/vorbis/vorbisdec.c @@ -761,10 +761,21 @@ static GstFlowReturn vorbis_handle_type_packet (GstVorbisDec * vd) { GList *walk; + int r; g_assert (vd->initialized == FALSE); - vorbis_synthesis_init (&vd->vd, &vd->vi); + fprintf(stderr,"vorbis_handle_type_packet: vd=%p\n", vd); + + r = vorbis_synthesis_init (&vd->vd, &vd->vi); + + if (r) + { + fprintf(stderr," failed init %d\n",r); + fprintf(stderr," vd->vd=%p, vd->vi=%p\n", vd->vd, vd->vi); + return GST_FLOW_WRONG_STATE; + } + I don't know what the correct GStreamer return should be but I guessed at GST_FLOW_WRONG_STATE, but certainly for this packet no decode should be attempted.
(In reply to comment #14) > Does it crash for you with the truncated file too? > Yes.
This code is called when it receives the 3th header packet and when it initializes the decoder. If this fails, things are pretty much broken. Maybe we misuse the API and it starts to break now with newer versions?
No, we're not misusing the API, it's just that the implementation is being stricter. Specifically, this was in this commit in libvorbis: michael@songbird-desktop:~/src/xiph/vorbis/lib$ svn log -c 14811 ------------------------------------------------------------------------ r14811 | xiphmont | 2008-04-28 14:42:52 -0700 (Mon, 28 Apr 2008) | 4 lines Additional bulletproofing to hufftree decoding; reject underpopulated trees up-front. ------------------------------------------------------------------------
(In reply to comment #20) > No, we're not misusing the API, it's just that the implementation is being > stricter. Specifically, this was in this commit in libvorbis: > > michael@songbird-desktop:~/src/xiph/vorbis/lib$ svn log -c 14811 > ------------------------------------------------------------------------ > r14811 | xiphmont | 2008-04-28 14:42:52 -0700 (Mon, 28 Apr 2008) | 4 lines > > Additional bulletproofing to hufftree decoding; reject underpopulated > trees up-front. > > > ------------------------------------------------------------------------ > I assume that the failure in vorbis_book_init_decode? Does this mean the crash I'm seeing is just because I have a more upto date libvorbis than previously? It still doesn't change the fact that Gstremer needs to deal with it gracefully rather than push on and let the codec crash. Or are you suggesting making the vorbis codec itself more bullet proof?
FWIW the file plays fine under Rockbox's vorbis implementation. I'm not sure what the conclusion should be, maybe one of the following: 1. The file is fine, gstreamer pushes the wrong data to vorbis, it gets confused and dies 2. The file is "broken" and a bad encoding, while older vorbis implementations are more tolerant of this breakage the current SVN head is not and gstreamer should handle this intolerance more gracefully.
Alex: yes, this is a gstreamer bug, I wasn't trying to say otherwise - just trying to track down the root cause. (2) appears to be the case - the file is invalid. However, perhaps libvorbis shouldn't be rejecting it - I've taken this up with upstream. Either way the gst bug should be fixed.
commit d1c73bd00f0befc6697c9d4afd6c363d59436941 Author: Wim Taymans <wim.taymans@collabora.co.uk> Date: Fri May 22 17:41:50 2009 +0200 vorbisdec: detect and report errors better Check the return values of a couple more libvorbis functions and post an error when something is wrong instead of continuing and crashing.
For what it's worth the exact bit of r14811 that trips up is: --- a/lib/sharedbook.c +++ b/lib/sharedbook.c @@ -124,7 +124,14 @@ ogg_uint32_t *_make_words(long *l,long n,long sparsecount){ }else if(sparsecount==0)count++; } - + + /* sanity check the huffman tree; an underpopulated tree must be rejected. */ + for(i=1;i<33;i++) + if(marker[i] & (0xffffffffUL>>(32-i))){ + _ogg_free(r); + return(NULL); + } + If I comment it out then vorbis and gstreamer play the file fine. Looking at an example table when "good" and "bad" it looks like a 1 bit error has crept in: Breakpoint 1, _make_words (l=0x1ed6b30, n=64, sparsecount=36) at sharedbook.c:138 138 fprintf(stderr,"markers are fine\n"); (gdb) x/33w marker 0x7fffc7cdcd40: 0x00000000 0x00000002 0x00000004 0x00000008 0x7fffc7cdcd50: 0x00000010 0x00000020 0x00000040 0x00000080 0x7fffc7cdcd60: 0x00000100 0x00000200 0x00000400 0x00000800 0x7fffc7cdcd70: 0x00001000 0x00002000 0x00004000 0x00008000 0x7fffc7cdcd80: 0x00010000 0x00020000 0x00040000 0x00080000 0x7fffc7cdcd90: 0x00100000 0x00200000 0x00400000 0x00800000 0x7fffc7cdcda0: 0x01000000 0x02000000 0x04000000 0x08000000 0x7fffc7cdcdb0: 0x10000000 0x20000000 0x40000000 0x80000000 0x7fffc7cdcdc0: 0x00000000 Compared with: vorbis_book_init_decode: 0x1ee5fe0, 0x1ed7510 n=1 _make_words: 0x1ed7580, 128, 1 Breakpoint 2, _make_words (l=0x1ed7580, n=128, sparsecount=1) at sharedbook.c:135 135 return(NULL); (gdb) x/30w marker 0x7fffc7cdcd40: 0x00000000 0x00000001 0x00000002 0x00000004 0x7fffc7cdcd50: 0x00000008 0x00000010 0x00000020 0x00000040 0x7fffc7cdcd60: 0x00000080 0x00000100 0x00000200 0x00000400 0x7fffc7cdcd70: 0x00000800 0x00001000 0x00002000 0x00004000 0x7fffc7cdcd80: 0x00008000 0x00010000 0x00020000 0x00040000 0x7fffc7cdcd90: 0x00080000 0x00100000 0x00200000 0x00400000 0x7fffc7cdcda0: 0x00800000 0x01000000 0x02000000 0x04000000 0x7fffc7cdcdb0: 0x08000000 0x10000000 Of course I don't fully understand the code yet so I have no idea if this is useful to the vorbis people.
(In reply to comment #24) > commit d1c73bd00f0befc6697c9d4afd6c363d59436941 > Author: Wim Taymans <wim.taymans@collabora.co.uk> > Date: Fri May 22 17:41:50 2009 +0200 > > vorbisdec: detect and report errors better > > Check the return values of a couple more libvorbis functions and post an > error > when something is wrong instead of continuing and crashing. > With the latest git HEAD (538c1cde31bf3189fe9d375aadb5e0089ae5acbe) I see the following: vorbis_book_init_decode: 0x1ed00e0, 0x1ec1760 n=1 _make_words: 0x1ec17d0, 128, 1 codes: (nil) vorbis_book_init_decode failed! vorbis_dsp_clear: vorbis_dsp_state (v)=0x1e0f2c8 vorbis_info (v->vi)=0x1e0f358 ERROR: from element /GstPipeline:pipeline0/GstDecodeBin2:decodebin20/GstVorbisDec:vorbisdec1: Could not decode stream. Additional debug info: vorbisdec.c(794): vorbis_handle_type_packet (): /GstPipeline:pipeline0/GstDecodeBin2:decodebin20/GstVorbisDec:vorbisdec1: couldn't initialize synthesis (1) ERROR: pipeline doesn't want to preroll. Setting pipeline to NULL ... Program received signal SIGFPE, Arithmetic exception.
+ Trace 215658
Thread 1094535504 (LWP 2489)
0x7f63543ed332 <res2_inverse+209>: idivl -0x30(%rbp) 0x7f63543ed335 <res2_inverse+212>: mov %eax,-0x1c(%rbp) 0x7f63543ed338 <res2_inverse+215>: mov -0x1c(%rbp),%eax 0x7f63543ed33b <res2_inverse+218>: cltq 0x7f63543ed33d <res2_inverse+220>: shl $0x3,%rax (gdb) p/x $rbp $1 = 0x413d33d0 (gdb) p $1-30 $2 = (void *) 0x413d33b2 (gdb) x/g $2 0x413d33b2: 0x0740000000000000 (gdb) x/w $2 0x413d33b2: 0x00000000 (gdb) Did you see the same result on your setup? As noted in previous comments making vorbis not trigger on that vorbis_book_init_decode results in the file playing OK. Are there any bugs/reports to the vorbis project I should be tracking?
The underlying libvorbis bug that was causing this particular file to be rejected has now been fixed upstream in xiph svn: r16073.
Thanks. I rolled up a new ebuild to apply svn16073: http://bugs.gentoo.org/show_bug.cgi?id=272364 And can confirm everything is working fine now. Of course the fixed vorbis no longer exercises the return value check code in Gstreamer which was causing me follow on crashes. Perhaps gstreamer needs some genuinely bad encode files for regression checks? However as far as the original bug is concerned I'm happy that this bug can be closed.