|
From: Zachary T. <div...@gm...> - 2009-07-14 16:54:04
|
Hello, I'm somewhat a valgrind noob, so apologies if this is a RTFM question. I did search around however and did not see anything definitive about this. I ran valgrind on an app I have and it generated thousands of spurious warnings. I know I can create a .supp file to suppress these, but my question is how do I know which ones are spurious and which ones are not? I found one website that mentioned that there was a .supp file somewhere in the valgrind code repository, but for some reason I cannot access the SVN repository. I'm using the correct SVN url (svn://svn.valgrind.org/valgrind/trunk), shown on the website at (http://www.valgrind.org/downloads/repository.html) but it just says the server timed out or did not respond appropriately. I've never had any problem accessing other svn repositories. Is there a way to tell which warnings are spurious to easily disable them, or is this .supp file which I can't seem to currently access the correct approach? 95% of the errors I get are either "Use of uninitialised value of size 4" (usually in _int_malloc, memcpy, or malloc_consolidate), and "Conditional jump or move depends on uninitialized value" (in anything have to do with static variable initialization / cleanup, etc). A slightly unrelated question is that valgrind doesn't always seem to report source / line number information for C++ STL functions. Is this normal? For example one of my warnings shows this: ==7439== Use of uninitialised value of size 4 ==7439== at 0x827A563: std::string::assign(std::string const&) (in /usr/sbin/snip/bin/snip) ==7439== <snipped> ==7439== <snipped> ==7439== by 0x826D023: std::ostream::flush() (in /usr/sbin/snip/bin/snip) ==7439== <snipped> ==7439== <snipped> ==7439== <snipped> ==7439== by 0x807A332: boost::_mfi::mf1<void, snip, snip*>::operator()(snip*, snip*) const (mem_fn_template.hpp:162) ==7439== by 0x807A4BD: void boost::_bi::list2<boost::_bi::value< snip*>, boost::_bi::value< snip*> >::operator()<boost::_mfi::mf1<void, snip, snip*>, boost::_bi::list0>(boost::_bi::type<void>, boost::_mfi::mf1<void, snip, snip*>&, boost::_bi::list0&, int) (bind.hpp:306) Here, the entire callstack shows line number information (including the lines I've snipped), except for the two STL calls. Is this normal? I suspect they might be inlined functions, but then again I would expect the boost code at the bottom to be inlined as well, so I don't think that's necessarily the issue. Thanks |
|
From: Colin M. <col...@pi...> - 2009-07-14 17:27:50
|
Zachary Turner wrote: > Hello, > > I'm somewhat a valgrind noob, so apologies if this is a RTFM question. > I did search around however and did not see anything definitive about > this. I ran valgrind on an app I have and it generated thousands of > spurious warnings. I know I can create a .supp file to suppress these, > but my question is how do I know which ones are spurious and which > ones are not? I found one website that mentioned that there was a > .supp file somewhere in the valgrind code repository, but for some > reason I cannot access the SVN repository. I'm using the correct SVN > url (svn://svn.valgrind.org/valgrind/trunk), shown on the website at > (http://www.valgrind.org/downloads/repository.html) but it just says > the server timed out or did not respond appropriately. I've never had > any problem accessing other svn repositories. > > Is there a way to tell which warnings are spurious to easily disable > them, or is this .supp file which I can't seem to currently access the > correct approach? 95% of the errors I get are either "Use of > uninitialised value of size 4" (usually in _int_malloc, memcpy, or > malloc_consolidate), and "Conditional jump or move depends on > uninitialized value" (in anything have to do with static variable > initialization / cleanup, etc). > > The short answer is *ALL* Valgrind reports are errors, and should be fixed. (with the possible exception of leaked reachable memory). Suppressions are there for reports inside third-party code that you can't fix. Valgrind comes with a set of suppressions for some standard libraries with are known to be buggy. Running valgrind -v /bin/true should print out the default suppressions that valgrind is using The lack of line numbers means the library does not have debug information with it. For Debian, try installing libstdc++*-dbg and libc6-dbg HTH, Colin S. Miller |
|
From: Zachary T. <div...@gm...> - 2009-07-14 17:49:00
|
On Tue, Jul 14, 2009 at 12:27 PM, Colin Miller<col...@pi...> wrote: > Zachary Turner wrote: >> Hello, >> >> I'm somewhat a valgrind noob, so apologies if this is a RTFM question. >> I did search around however and did not see anything definitive about >> this. I ran valgrind on an app I have and it generated thousands of >> spurious warnings. I know I can create a .supp file to suppress these, >> but my question is how do I know which ones are spurious and which >> ones are not? I found one website that mentioned that there was a >> .supp file somewhere in the valgrind code repository, but for some >> reason I cannot access the SVN repository. I'm using the correct SVN >> url (svn://svn.valgrind.org/valgrind/trunk), shown on the website at >> (http://www.valgrind.org/downloads/repository.html) but it just says >> the server timed out or did not respond appropriately. I've never had >> any problem accessing other svn repositories. >> >> Is there a way to tell which warnings are spurious to easily disable >> them, or is this .supp file which I can't seem to currently access the >> correct approach? 95% of the errors I get are either "Use of >> uninitialised value of size 4" (usually in _int_malloc, memcpy, or >> malloc_consolidate), and "Conditional jump or move depends on >> uninitialized value" (in anything have to do with static variable >> initialization / cleanup, etc). >> >> > The short answer is *ALL* Valgrind reports are errors, and should be > fixed. > (with the possible exception of leaked reachable memory). > > Suppressions are there for reports inside third-party code that you > can't fix. > > Valgrind comes with a set of suppressions for some standard libraries > with are known to be buggy. > > Running > valgrind -v /bin/true > should print out the default suppressions that valgrind is using > > > The lack of line numbers means the library does not have debug > information with it. > For Debian, try installing > libstdc++*-dbg and libc6-dbg > > > HTH, > Colin S. Miller Hi, thanks for the info about the debug libraries. Regarding your point about fixing all errors, I get thousands of errors that happen during process initialization. Just to give a couple examples: ==7373== Syscall param set_robust_list(head) points to uninitialised byte(s) ==7373== at 0x82A8C61: __pthread_initialize_minimal (in /usr/sbin/snip/bin/snip) ==7373== by 0x82A8FCC: (below main) (in /usr/sbin/snip/bin/snip) ==7373== Address 0x83FC898 is not stack'd, malloc'd or (recently) free'd ==7373== Conditional jump or move depends on uninitialised value(s) ==7373== at 0x82EA155: __register_atfork (in /usr/sbin/snip/bin/snip) ==7373== by 0x82EA26A: __libc_pthread_init (in /usr/sbin/snip/bin/snip) ==7373== by 0x82A8E19: __pthread_initialize_minimal (in /usr/sbin/snip/bin/snip) ==7373== by 0x82A8FCC: (below main) (in /usr/sbin/snip/bin/snip) ==7373== Conditional jump or move depends on uninitialised value(s) ==7373== at 0x82D4E22: malloc (in /usr/sbin/snip/bin/snip) ==7373== by 0x82D4DE7: malloc (in /usr/sbin/snip/bin/snip) ==7373== by 0x830A5DB: _dl_init_paths (in /usr/sbin/snip/bin/snip) ==7373== by 0x82ED78B: _dl_non_dynamic_init (in /usr/sbin/snip/bin/snip) ==7373== by 0x82EE065: __libc_init_first (in /usr/sbin/snip/bin/snip) ==7373== by 0x82A9050: (below main) (in /usr/sbin/snip/bin/snip) ==7439== Use of uninitialised value of size 4 ==7439== at 0x82D32D6: _int_malloc (in /usr/sbin/snip/bin/snip) ==7439== by 0x82D4E3A: malloc (in /usr/sbin/snip/bin/snip) ==7439== by 0x82992E6: operator new(unsigned) (in /usr/snip/snip/bin/snip) ==7439== by 0x827945A: std::string::_Rep::_S_create(unsigned, unsigned, std::allocator<char> const&) (in /usr/sbin/snip/bin/snip) ==7439== by 0x8279D5C: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned) (in /usr/snip/snip/snip/snip) ==7439== by 0x827A659: std::string::reserve(unsigned) (in /usr/sbin/snip/bin/snip) ==7439== by 0x827A77C: std::string::append(unsigned, char) (in /usr/sbin/snip/bin/snip) ==7439== by 0x827B80F: std::string::resize(unsigned) (in /usr/sbin/snip/bin/snip) ==7439== by 0x80D8153: Foo::Foo(x&, y const&) (Foo.cpp:147) ==7439== by 0x80D4C96: Foo::foi(x&, y const&) (Foo.cpp:234) ==7439== by 0x80D7006: Foo::foj(RsaKeyInfo&) (Foo.cpp:60) ==7439== by 0x80CF313: Bar::Baz() (Bar.cpp:141) The first few all have their roots in libc, and the last one, while it does at least have my code on the callstack, is really nothing special. For example, Foo::Foo (Foo.cpp:147) listed above is basically just the following: class Foo { Foo(x&, const y) { std::stringstream input_buf; //initialize input_buf using whatever method unsigned short length; input_buf.read((char*)&length, sizeof(length)); length = ntohs(length); str_.resize(length); } private: std::string str_; }; So unless libstdc++ has some kind of error in it, I'm not sure what else I can do. Could it be that that there's some switch I can compile my program with, or some switch I can run valgrind with to make the results more accurate? Or do these still look like legitimate errors that should be fixed somehow (even if "fixed" turns out to mean "you built your libraries incorrectly, rebuild them" )? |
|
From: Zachary T. <div...@gm...> - 2009-07-14 18:20:33
|
On Tue, Jul 14, 2009 at 1:07 PM, Colin Miller<col...@pi...> wrote:
> Zachary Turner wrote:
>>
>> On Tue, Jul 14, 2009 at 12:27 PM, Colin Miller<col...@pi...>
>> wrote:
>>
>> ==7439== Use of uninitialised value of size 4
>> ==7439== at 0x82D32D6: _int_malloc (in /usr/sbin/snip/bin/snip)
>> ==7439== by 0x82D4E3A: malloc (in /usr/sbin/snip/bin/snip)
>> ==7439== by 0x82992E6: operator new(unsigned) (in
>> /usr/snip/snip/bin/snip)
>> ==7439== by 0x827945A: std::string::_Rep::_S_create(unsigned,
>> unsigned, std::allocator<char> const&) (in /usr/sbin/snip/bin/snip)
>> ==7439== by 0x8279D5C:
>> std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned) (in
>> /usr/snip/snip/snip/snip)
>> ==7439== by 0x827A659: std::string::reserve(unsigned) (in
>> /usr/sbin/snip/bin/snip)
>> ==7439== by 0x827A77C: std::string::append(unsigned, char) (in
>> /usr/sbin/snip/bin/snip)
>> ==7439== by 0x827B80F: std::string::resize(unsigned) (in
>> /usr/sbin/snip/bin/snip)
>> ==7439== by 0x80D8153: Foo::Foo(x&, y const&) (Foo.cpp:147)
>> ==7439== by 0x80D4C96: Foo::foi(x&, y const&) (Foo.cpp:234)
>> ==7439== by 0x80D7006: Foo::foj(RsaKeyInfo&) (Foo.cpp:60)
>> ==7439== by 0x80CF313: Bar::Baz() (Bar.cpp:141)
>>
>>
>> The first few all have their roots in libc, and the last one, while it
>> does at least have my code on the callstack, is really nothing
>> special. For example, Foo::Foo (Foo.cpp:147) listed above is
>> basically just the following:
>>
>> class Foo
>> {
>> Foo(x&, const y)
>> {
>> std::stringstream input_buf;
>> //initialize input_buf using whatever method
>>
>> unsigned short length;
>> input_buf.read((char*)&length, sizeof(length));
>> length = ntohs(length);
>> str_.resize(length);
>> }
>> private:
>> std::string str_;
>> };
>>
>>
>
> It's been a while since I've done C++,
> but IIRC, the stream input_buf hasn't had a string associated with it.
> Therefore the read() will read 0 bytes,
> and the variable 'length'
> with be uninitialised
>
> Now assuming that this is just an artefact of stripping the code for display
> here,
> it might be worthwhile calling
> |VALGRIND_CHECK_MEM_IS_DEFINED(length, 4)
> just before the resize(length).
> Prototype is in valgrind/memcheck.h
>
> This will verify that 'length' has been properly initialised.
>
> HTH,
> Colin S. Miller
Thanks! I'll definitely give that a shot, I didn't know about that.
I don't guess this could have anything to do with converting smaller
types to larger types could it? For example, above I've defined
length as a 2-byte value, but then passing it (by value) to a function
which takes a 4-byte value.
Also, for what it's worth, the value _is_ actually uninitialized
except that I pass it to that input_buf.read() method by pointer which
does raw modification of the memory. Is valgrind able to detect this?
In other words, how much dynamic analysis is it actually doing? Is
it actually detecting writes to individual bytes of memory and then
tagging each byte as 'dirty', and verifying for every read that
occurs, that every byte being read from is dirty?
Suppose, for example, that I do the following:
//Process 1
//1. Map a 256-byte region in shared memory.
//2. Wait on a shared condition variable.
//3. Read 256-bytes from the shared memory
//Process 2
//1. Map the same 256-byte region in shared memory.
//2. Write 256-bytes into the shared memory
//3. Signal the shared condition variable
Will valgrind correctly note in this case that the data is
initialized? I bring up this specific scenario because this way
valgrind presumably has no correlation between the two process's
source codes / debug information and would be unable to perform any
static analysis whatsoever. Whereas the example I'm actually
encountering above with the length variable is the same in the sense
that it's relying on non-type-safe, external memory modification, but
it could still in theory be detected with some static analysis.
Also, any suggestions about the libc errors? Those don't have any of
my code on the stack at all. (I'm also not using the most recent
version of Valgrind, I'm using 3.1.x, is there a huge difference?)
|
|
From: John R.
|
> I'm also not using the most recent > version of Valgrind, I'm using 3.1.x, is there a huge difference? Yes, there is a *huge* difference: three years worth of work. valgrind-3.1.1: 15 March 2006 valgrind-3.4.1: 28 February 2009 -- |