Bug 1250 - Malformed VCD causes infinite memory allocation loop
Summary: Malformed VCD causes infinite memory allocation loop
Status: RESOLVED FIXED
Alias: None
Product: PulseView
Classification: Unclassified
Component: File handling (show other bugs)
Version: unreleased development snapshot
Hardware: x86 Linux
: Normal normal
Target Milestone: ---
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-07-21 22:18 CEST by Brian Starkey
Modified: 2018-07-22 16:26 CEST (History)
2 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Brian Starkey 2018-07-21 22:18:24 CEST
Pulseview built from git: PulseView 0.5.0-git-1b856fb, but also affected my previous version 5a20644617a727e5893cd1df3f105135c1ebdedd.
Arch Linux, x86



I've been tracking down what's causing Pulseview to lock up and eat up all my RAM, and it turns out that my VCD was malformed.

It looks like if there are timestamps in the VCD, and they aren't in the correct order, then Pulseview loops inifinitely in add_samples(). Here's a minimal VCD which exhibits this issue (Warning! If you run this, you likely won't be able to kill Pulseview. Best to do it in a debugger, or be ready to 'kill -9' quickly!):

$timescale 10 us $end
$var wire 1 ! pin0 $end
$var wire 1 " pin1 $end
$enddefinitions $end
#0 1! 
#2 0! 
#1 1" 


The actual value changes don't seem to matter - only that a timestamp occurs out-of-order.


Backtrace of the offending thread, interrupted at a random time:

#0  0x0000555555628224 in pv::data::LogicSegment::append_payload_to_mipmap() (this=this@entry=0x7fffc4403380)
    at /aux/sources/pulseview/pv/data/logicsegment.cpp:250
#1  0x0000555555628382 in pv::data::LogicSegment::append_payload(void*, unsigned long) (this=0x7fffc4403380, data=0x5555561ddc30, data_size=<optimized out>) at /aux/sources/pulseview/pv/data/logicsegment.cpp:162                                                                      
#2  0x000055555562841f in pv::data::LogicSegment::append_payload(std::shared_ptr<sigrok::Logic>) (this=<optimized out>, logic=...)
    at /usr/include/c++/8.1.1/bits/shared_ptr_base.h:1002
#3  0x0000555555610f93 in pv::Session::feed_in_logic(std::shared_ptr<sigrok::Logic>) (this=0x555555ab2630, logic=std::shared_ptr<sigrok::Logic> (use count 3, weak count 1) = {...}) at /usr/include/c++/8.1.1/ext/atomicity.h:96                                                        
#4  0x0000555555611dcd in pv::Session::data_feed_in(std::shared_ptr<sigrok::Device>, std::shared_ptr<sigrok::Packet>) (this=0x555555ab2630, device=std::shared_ptr<sigrok::Device> (use count 13, weak count 1) = {...}, packet=std::shared_ptr<sigrok::Packet> (use count 3, weak count 1
) = {...}) at /usr/include/c++/8.1.1/ext/atomicity.h:96
#5  0x0000555555612263 in pv::Session::<lambda(std::shared_ptr<sigrok::Device>, std::shared_ptr<sigrok::Packet>)>::operator() (__closure=<optimized out>, packet=..., device=...) at /usr/include/c++/8.1.1/ext/atomicity.h:96                                                           
#6  0x0000555555612263 in std::_Function_handler<void (std::shared_ptr<sigrok::Device>, std::shared_ptr<sigrok::Packet>), pv::Session::set_device(std::shared_ptr<pv::devices::Device>)::{lambda(std::shared_ptr<sigrok::Device>, std::shared_ptr<sigrok::Packet>)#1}>::_M_invoke(std::_An
y_data const&, std::shared_ptr<sigrok::Device>&&, std::shared_ptr<sigrok::Packet>&&) (__functor=..., __args#0=..., __args#1=...)
    at /usr/include/c++/8.1.1/bits/std_function.h:297
#7  0x00007ffff6e1d75d in std::function<void (std::shared_ptr<sigrok::Device>, std::shared_ptr<sigrok::Packet>)>::operator()(std::shared_ptr<sigrok::Device>, std::shared_ptr<sigrok::Packet>) const (__args#1=<error reading variable: Cannot access memory at address 0xffffffffcd800009
>, __args#0=std::shared_ptr<sigrok::Device> (empty) = {...}, this=0x555555f67650) at /usr/include/c++/8.1.1/bits/std_function.h:682
#8  0x00007ffff6e1d75d in sigrok::DatafeedCallbackData::run(sr_dev_inst const*, sr_datafeed_packet const*) (this=0x555555f67650, sdi=<optimized out>, pkt=<optimized out>) at bindings/cxx/classes.cpp:900                                                                               
#9  0x00007ffff6b0f8cf in sr_session_send (sdi=0x555555eaf010, packet=packet@entry=0x7fffd486bb60) at src/session.c:1150
#10 0x00007ffff6b1ca77 in send_buffer (in=<optimized out>, in=<optimized out>) at src/input/vcd.c:310
#11 0x00007ffff6b1cf3a in add_samples (count=<optimized out>, in=0x555555f0d580) at src/input/vcd.c:343
#12 0x00007ffff6b1cf3a in parse_contents (data=<optimized out>, in=0x555555f0d580) at src/input/vcd.c:420
#13 0x00007ffff6b1cf3a in process_buffer (in=<optimized out>) at src/input/vcd.c:555
#14 0x00007ffff6b1d145 in end (in=0x555555f0d580) at src/input/vcd.c:595
#15 0x00007ffff6e1421d in sigrok::Input::end() (this=<optimized out>) at bindings/cxx/classes.cpp:1471
#16 0x0000555555633b92 in pv::devices::InputFile::run() (this=0x55555605fcd0) at /aux/sources/pulseview/pv/devices/inputfile.cpp:186
#17 0x000055555560b8f0 in pv::Session::sample_thread_proc(std::function<void (QString)>) (this=0x555555ab2630, error_handler=...)
    at /usr/include/c++/8.1.1/bits/shared_ptr_base.h:1002
#18 0x000055555561250f in std::__invoke_impl<void, void (pv::Session::*)(std::function<void (QString)>), pv::Session*, std::function<void (QString)> >(std::__invoke_memfun_deref, void (pv::Session::*&&)(std::function<void (QString)>), pv::Session*&&, std::function<void (QString)>&&
) (__t=<optimized out>, __f=<optimized out>) at /usr/include/c++/8.1.1/bits/move.h:182
#19 0x000055555561250f in std::__invoke<void (pv::Session::*)(std::function<void (QString)>), pv::Session*, std::function<void (QString)> >(void (pv::Session::*&&)(std::function<void (QString)>), pv::Session*&&, std::function<void (QString)>&&) (__fn=<optimized out>)              
    at /usr/include/c++/8.1.1/bits/invoke.h:95
#20 0x000055555561250f in std::thread::_Invoker<std::tuple<void (pv::Session::*)(std::function<void (QString)>), pv::Session*, std::function<void (QString)> > >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) (this=<optimized out>) at /usr/include/c++/8.1.1/thread:234 
#21 0x000055555561250f in std::thread::_Invoker<std::tuple<void (pv::Session::*)(std::function<void (QString)>), pv::Session*, std::function<void (QString)> > >::operator()() (this=<optimized out>) at /usr/include/c++/8.1.1/thread:243                                               
#22 0x000055555561250f in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (pv::Session::*)(std::function<void (QString)>), pv::Session*, std::function<void (QString)> > > >::_M_run() (this=<optimized out>) at /usr/include/c++/8.1.1/thread:186                        
#23 0x00007ffff4521d4f in execute_native_thread_routine (__p=0x555555fd5db0) at /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80
#24 0x00007ffff703f075 in start_thread () at /usr/lib/libpthread.so.0
#25 0x00007ffff3bf653f in clone () at /usr/lib/libc.so.6
Comment 1 Gerhard Sittig 2018-07-21 23:17:31 CEST
Can you try git://repo.or.cz/libsigrok/gsi.git vcd-time-back-1250 please? 
(http://repo.or.cz/libsigrok/gsi.git/shortlog/refs/heads/vcd-time-back-1250) 
It may take a moment to land in mainline.

The issue is that a 64bit counter starts at 2 and increments until it would 
reach value 1, which results in a lot of iterations ...

Was the troublesome input file created manually?  Or was some generator 
emitting this invalid data?
Comment 2 Brian Starkey 2018-07-21 23:29:16 CEST
Works for me, thanks for the super speedy fix!

The VCD is being generated by some (buggy) code I wrote, so mea culpa there. I guess it's still good for libsigrok to be defensive against idiots like me :-)

Thanks again,
-Brian
Comment 3 Uwe Hermann 2018-07-22 16:26:38 CEST
Fixed in ed367d68203593224af3c9593cfef0662b56007c, thanks!