Catching Strange C-Arithmetic Error Pointers

Recently, I came across a very insightful error in which I forgot to dereference a pointer to a string (char array) and thus sometimes overwrite one byte on the stack.

Poorly:

char ** str; (*str) = malloc(10); ... str[2] = 'a'; //overwrites 3 bytes from the location in which str is stored 

Fixed:

 char ** str; (*str) = malloc(10); ... (*str)[2] = 'a'; 

GCC did not issue any warnings, and this error would lead to a very serious and real exploit, since the value that it sometimes overwritten contained the size of the buffer. I just caught this error because I was lucky and it caused a clear failure.

  • Also, to rely on luck and / or never use C for anything, what protective methods and coding tricks do you use to catch creepy C errors?

  • I'm thinking of switching to valgrind MemCheck , has anyone used it? I suspect I would not catch this mistake. Somebody knows?

  • Are there tools for finding dereferencing pointers or arithmetic errors? Is it possible?

UPDATE

Here is the requested sample code; it does not give any warnings.

 #include <stdlib.h> void test(unsigned char** byteArray){ (*byteArray) = (unsigned char*)malloc(5); byteArray[4] = 0x0; } int main(void){ unsigned char* str; test(&str); return 0; } 

Compilation does not cause errors:

 gcc -Wall testBug.c -o testBug 

Running causes a seg error:

 ./testBug Segmentation fault 

This is the version of GCC I am using:

 gcc -v Using built-in specs. Target: i486-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.1-4ubuntu9' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu Thread model: posix gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9) 
+7
c pointers findbugs
source share
5 answers

My best defense pointer strategy: Strictly avoid using more than one level of indirection. Allocation of a pointer to a pointer for assigning memory to it in order. But then use the assigned memory as the array asks for the problems you have. I would do something like:

 char **outStr; *outStr = malloc(10); char *str = *outStr; str[2] = 10; 

Well, it's actually just a health strategy that also has defensive value. Pointers are pretty easy to understand when there is no more than one level of indirection at a time, and it's easier to get the code right when you understand it well.

+3
source share

I use Valgrind, it's a lifesaver!

 valgrind --tool=memcheck -v ./yourapp 

And MemCheck will detect that you have an invalid entry with `str [2] = 'a'; '.

+1
source share

Gcc should give you

  warning: assignment makes pointer from integer without a cast 

Not

+1
source share

Please use Valgrind. This is one of the best memory checking tools I've come across. He will surely find your mistake.

Besides detecting memory errors, valgrind also helps in detecting memory leaks, used memory blocks, etc.

Even IBM Rational Purify can help you find such errors. Although my personal favorite is Valgrind.

+1
source share

My suggestion is not a tool, but a best practice: testing. Such errors are usually very easy to find with rigorous code testing, starting with the lowest level of unit testing.

The code you show will never lead to the correct result - this is not something that sometimes works, and sometimes not. Having a unit test for this part of the code can save you debugging hours later when it is integrated with other parts of the system.

Unit testing can be supplemented by coverage testing: either using an automatic tool, or just manually scanning the code and writing tests designed for each part is a great way to re-read your code (another debugging tool) and is surprisingly effective.

0
source share

All Articles