3 ms·
C++ compilers will actually warn you about plenty of memory issues if you ask them to, by writing type-safe code and turning on lots of warnings. Static analyz
by leif 15y ago
C++ compilers will actually warn you about plenty of memory issues if you ask them to, by writing type-safe code and turning on lots of warnings. Static analyzers today are very good, and will catch a surprisingly good amount of unsafe memory problems that even the compilers miss. The rope it gives you is there for people that need it, but if you don't want it lying around because you're afraid you'll hang yourself, you can always ask the compiler to take it away.
- yaakov34 15y agoI might not be quite up to date, and I don't usually write extremely buggy code which compilers yell at, but have compilers really started warning on something like "vector_reference.push_back(&local_object);"? There are lots of ways to go wrong with unsafe memory access, and yes, there are tools to help you (things like valgrind help more than compiler warnings), but I think that the saying "hey, they gave you enough rope" is really unsatisfying. We've lived through 20 years of constant vulnerabilities because of these issues, and this only now starting to get sort of addressed. If virtually every team on the planet finds itself unable to use a certain tool "properly", then it's the tool which is being wrongly deployed, it's not the fault of everyone on the planet. And I agree that the tool has a lot of usefulness in many places; obviously, you can't write system software without the ability to manipulate chunks of memory and the stack and everything else. But C++ is used as a universal programming language, and has tons of features which were not made for system programming, but for application programming. So on the one hand C++ has this extreme safety-oriented pedantry in which you have to decide if your design will have a reference to a const iterator or a const pointer or what, and on the other hand, you can cast that object to (void *) and write Stroustrup's picture to it. Personally, I'd like to see a world in which the core system is written in a systems language like C/C++, and most libraries and all applications are managed code. Microsoft was working on something like this a few years ago, and I guess Android is sort of a step in that direction, but I think we won't get there for a long time. But it has to happen eventually, since we can't live with the vulnerabilities.
- leif 15y agogcc 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.