3 ms·
gcc 4.6 warns about returning the address of a local variable by default (you don't even need -Wall): % cat foo.c #include <stdio.h> int *bad(void)
by leif 15y ago
gcc 4.6 warns about returning the address of a local variable by default (you don't even need -Wall):
% cat foo.c
#include <stdio.h>
int *bad(void) { int a = 42; return &a; }
int main(void) { int *p = bad(); printf("%d\n", *p); return 0; }
% gcc foo.c
foo.c: In function ‘bad’:
foo.c:2:30: warning: function returns address of local variable [enabled by default]
g++ 4.6 doesn't catch the error you mentioned, but valgrind does:
% cat bar.cc
#include <iostream>
#include <vector>
using std::vector;
using std::cout;
void bar(vector<int *> &v) {
int a = 42;
v.push_back(&a);
}
int main(void) {
vector<int *> v;
bar(v);
cout << *v[0];
return 0;
}
% g++ bar.cc
% valgrind --track-origins=yes ./a.out
...
==8210== Conditional jump or move depends on uninitialised value(s)
==8210== at 0x4EBAFE4: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/libstdc++.so.6.0.16)
==8210== by 0x4EBB305: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (in /usr/lib/libstdc++.so.6.0.16)
==8210== by 0x4EC62BC: std::ostream& std::ostream::_M_insert<long>(long) (in /usr/lib/libstdc++.so.6.0.16)
==8210== by 0x400B98: main (in /home/leif/a.out)
==8210== Uninitialised value was created by a stack allocation
==8210== at 0x400B78: main (in /home/leif/a.out)
...
I don't know how hard it is to use valgrind "properly". I ran it with no arguments and it gave me the error, and even told me to add --track-origins=yes. If you're writing code that needs to be even remotely reliable and you aren't using valgrind, what the hell are you using?
- yaakov34 15y agoBelieve me, on a lot of examples of real-world code, valgrind &co. will find false positives and miss errors. I've been there and done that. And then you can't pick out the signal from the noise. Again, if just about every team on the planet has trouble with this, then it's not a question of just running some tool. And of course we use valgrind and a bunch of other standard and custom tools. I said myself that valgrind will help here, so it's not like you need to read me the whole kindergarten primer on this.
- leif 15y agoSorry, I don't mean to be patronizing. You asked whether the compiler catches it, it didn't, but valgrind did so I showed that. Of course valgrind and friends have false positives, but in other languages where these errors are compile errors, you can't suppress them when you need to, instead, you just can't write that code, even if you've been alerted to the issue and know it's ok. Of the software teams I do know, every one that was writing C/C++ (including my current one) incorporated valgrind and other tools into their build/test framework, and had no problems separating signal from noise. I don't know that many though, I'm still young. Do you know of software teams developing critical software that are unable to check their C code for memory errors automatically?
- yaakov34 15y agoI apologize that I got testy, I just don't think there is a need to paste the whole valgrind run into the message. Anyway, problem #1 is that valgrind is not a code-coverage tool - it only sees the execution path that just happened. You can, of course, combine it with a code-coverage tool, and people do, but code coverage is an incredibly difficult thing, since a huge number of code paths just don't happen in any normal execution. And those are the dangerous ones, both for malware attacks and for reliability. Problem #2, which is smaller, is that valgrind is just not that perfect - for real-life code with foreign-language interfaces, real-time driver accesses, and so on and so on, it will give false positives and false negatives. This is why it has a feature where it takes a humongous error-suppression file to stop it from showing you things that you're not interested in. That's not a perfect solution. I'm not saying there is nothing you can do - of course you can, and for well-defined projects with strong security goals and very large resources, you can get to excellent security. But even the Sun JVM had buffer overflows, I seem to remember. Those guys have heard of valgrind. If there was a button that someone could push to make C/C++ lack of memory safety stop mattering, it would have been pushed by now.
- leif 15y agodon't worry, I understand, I pasted it for others Yeah, it's not perfect, but nothing we have is. I don't know what more to say. It works pretty well for most things I've seen. Do you have any examples of projects which can't use something like valgrind for some reason, not just those for which it wasn't magic pixie dust?