I have a simple program (a VERY simplistic malloc/free implementation, originally written for a university assignment), which has to check the "validity" of the pointers in the free, for which I need to dereference it. To avoid Segfaults when a user supplies a bs pointer, I want to check if the memory is currently mapped into my Addressspace.
I wanted to do this with something like
char* pointer_to_memory;
free(void *ptr) {
if((uintptr_t)ptr < (uintptr_t)pointer_to_memory) {
abort();
}
}
Now, the problem is, that c11 has uintptr_t as an optional feature, meaning not all compiler support that. I don't really NEED the code, so I would be willing to just leave it out when compiling with a compiler that doesn't support uintptr_t with some kind of preprocessor magic. I know, that pointer to integer casts are not always working like one would expect them to (ARM seems to have some additional info in the pointers for Example) but it seemed better defined than (direct) pointer comparisons. I also can't just ignore the SIGSEGV, since I want to stay true to the university assignment and we were not allowed to use Signal Handlers (and I suspect a SIGSEGV hander is not something you should overwrite as a free)
CodePudding user response:
I would be willing to just leave it out when compiling with a compiler that doesn't support uintptr_t with some kind of preprocessor magic.
As pointed out by
n. 1.8e9-where's-my-share m, you can use UINTPTR_MAX
:
char* pointer_to_memory;
free(void *ptr)
{
#if defined(UINTPTR_MAX)
if((uintptr_t)ptr < (uintptr_t)pointer_to_memory) {
abort();
}
#endif
// ...
}
To avoid Segfaults when a user supplies a bs pointer, I want to check if the memory is currently mapped into my Addressspace.
You cannot force the user to write "correct" programs in C. If C, by design, allows somebody to shoot themselves in the foot, you will never be able stop them programatically.
CodePudding user response:
There are two ways you can detect optional features.
One of them is checking a preprocessor macro. If (and that's is a strong if) your compiler is following a standard, you can expect some preprocessor macro to be set depending on the faeture. For uintptr_t
that would be UINTPTR_MAX
from stdint.h
file.
Some compilers do not follow a standard. For example, a compiler may give you uintptr_t
without UINTPTR_MAX
.
The second thing is to compile an example program that uses the feature, remember if the compilation suceeded, and then set a custom preprocessor macro or different action when compiling your code. This is the way build systems work. Autotools has AC_COMPILE_IFELSE
, CMake has try_compile
to check a compilation of a program. Then depending on the result of compilation, set a preprocessor macro in your program, or in case of autotools, you would generate a different config.h
file.
// CMakeLists.txt
string(APPEND CMAKE_REQUIRED_INCLUDES "stdint.h" "limits.h")
include(CheckTypeSize)
check_type_size("uintptr_t" UINTPTR)
if(HAVE_UINTPTR)
target_compile_definition(yourlib PREFIX_HAS_UINTPTR)
endif()
// your C code
#ifdef PREFIX_HAS_UINTPTR
// use uintptr_t
#endif