In C/C++, there is no general solution. You can't do it at compile time since there are too many ways to change memory in C. Example:
char * ptr = &array2;
ptr = foo(ptr); // ptr --;
ptr
now contains a valid address but the address is outside of array2
. This can be a bug or what you want. C can't know (there is no way to say "I want it so" in C), so the compiler can't check it. Sililarily:
char * array2 = malloc(100);
How should the C compiler know that you are treating the memory as a char array and would like a warning when you write &array2[100]
?
Therefore, most solutions use "mungwalls", i.e. when you call malloc()
, they will actually allocate 16/32 bytes more than you ask for:
malloc(size) {
mungwall_size = 16;
ptr = real_malloc(size + mungwall_size*2);
createMungwall(ptr, mungwall_size);
createMungwall(ptr+size, mungwall_size);
return ptr+size;
}
in free()
it will check that 16 bytes before and after the allocated memory area haven't been touched (i.e. that the mungwall pattern is still intact). While not perfect, it makes your program crash earlier (and hopefully closer to the bug).
You could also use special CPU commands to check all memory accesses but this approach would make your program 100 to 1 million times slower than it is now.
Therefore, languages after C don't allow pointers which means "array" is a basic type which has a size. Now, you can check every array access with a simple compare.
If you want to write code in C which is save, you must emulate this. Create an array type, never use pointers or char *
for strings. It means you must convert your data type all the time (because all library functions use const char *
for strings) but it makes your code safer.
Languages do age. C is now 40 years old and our knowledge has moved on. It's still used in a lot of places but it shouldn't be the first choice anymore. The same applies (to a lesser extend) to C++ because it suffers from the same fundamental flaws of C (even though you now have libraries and frameworks which work around many of them).