Can we check whether a pointer passed to a function is allocated with memory or not in C?
I have wriiten my own function in C which accepts a character pointer -
You can't check with anything available in standard C. Even if your specific compiler were to provide a function to do so, it would still be a bad idea. Here's an example of why:
int YourFunc(char * buf, int buf_size);
char str[COUNT];
result = YourFunc(str, COUNT);
in general lib users are responsible for input check and verification. You may see ASSERT or something in the lib code and they are used only for debug perpose. it is a standard way when writing C/C++. while so many coders like to do such check and verfying in their lib code very carefully. really "BAD" habits. As stated in IOP/IOD, lib interfaces should be the contracts and make clear what will the lib do and what will not, and what a lib user should do and what should be not necessary.
There is a simple way to do this. Whenever you create a pointer, write a wrapper around it. For example, if your programmer uses your library to create a structure.
struct struct_type struct_var;
make sure he allocates memory using your function such as
struct struct_type struct_var = init_struct_type()
if this struct_var contains memory that is dynamically allocated, for ex,
if the definition of struct_type was
typedef struct struct_type {
char *string;
}struct_type;
then in your init_struct_type() function, do this,
init_struct_type()
{
struct struct_type *temp = (struct struct_type*)malloc(sizeof(struct_type));
temp->string = NULL;
return temp;
}
This way,unless he allocates the temp->string to a value, it will remain NULL. You can check in the functions that use this structure, if the string is NULL or not.
One more thing, if the programmer is so bad, that he fails to use your functions, but rather directly accesses unallocated the memory, he doesn't deserve to use your library. Just ensure that your documentation specifies everything.
No, you can't. You'll notice that no functions in the standard library or anywhere else do this. That's because there's no standard way to tell. The calling code just has to accept responsibility for correctly managing the memory.
A pointer tracker, tracks and checks the validity of a pointer
usage:
create memory int * ptr = malloc(sizeof(int) * 10);
add the pointer address to the tracker Ptr(&ptr);
check for failing pointers PtrCheck();
and free all trackers at the end of your code
PtrFree();
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
struct my_ptr_t { void ** ptr; size_t mem; struct my_ptr_t *next, *previous; };
static struct my_ptr_t * ptr = NULL;
void Ptr(void * p){
struct my_ptr_t * tmp = (struct my_ptr_t*) malloc(sizeof(struct my_ptr_t));
printf("\t\tcreating Ptr tracker:");
if(ptr){ ptr->next = tmp; }
tmp->previous = ptr;
ptr = tmp;
ptr->ptr = p;
ptr->mem = **(size_t**) ptr->ptr;
ptr->next = NULL;
printf("%I64x\n", ptr);
};
void PtrFree(void){
if(!ptr){ return; }
/* if ptr->previous == NULL */
if(!ptr->previous){
if(*ptr->ptr){
free(ptr->ptr);
ptr->ptr = NULL;
}
free(ptr);
ptr = NULL;
return;
}
struct my_ptr_t * tmp = ptr;
for(;tmp != NULL; tmp = tmp->previous ){
if(*tmp->ptr){
if(**(size_t**)tmp->ptr == tmp->mem){
free(*tmp->ptr);
*tmp->ptr = NULL;
}
}
free(tmp);
}
return;
};
void PtrCheck(void){
if(!ptr){ return; }
if(!ptr->previous){
if(*(size_t*)ptr->ptr){
if(*ptr->ptr){
if(**(size_t**) ptr->ptr != ptr->mem){
printf("\tpointer %I64x points not to a valid memory address", ptr->mem);
printf(" did you freed the memory and not NULL'ed the pointer or used arthmetric's on pointer %I64x?\n", *ptr->ptr);
return;
}
}
return;
}
return;
}
struct my_ptr_t * tmp = ptr;
for(;tmp->previous != NULL; tmp = tmp->previous){
if(*(size_t*)tmp->ptr){
if(*tmp->ptr){
if(**(size_t**) tmp->ptr != tmp->mem){
printf("\tpointer %I64x points not to a valid memory address", tmp->mem);
printf(" did you freed the memory and not NULL'ed the pointer or used arthmetric's on pointer %I64x?\n", *tmp->ptr); continue;
}
}
continue;
}
}
return;
};
int main(void){
printf("\n\n\t *************** Test ******************** \n\n");
size_t i = 0;
printf("\t *************** create tracker ********************\n");
int * ptr = malloc(sizeof(int) * 10);
Ptr(&ptr);
printf("\t *************** check tracker ********************\n");
PtrCheck();
printf("\t *************** free pointer ********************\n");
free(ptr);
printf("\t *************** check tracker ********************\n");
PtrCheck();
printf("\t *************** set pointer NULL *******************\n");
ptr = NULL;
printf("\t *************** check tracker ********************\n");
PtrCheck();
printf("\t *************** free tracker ********************\n");
PtrFree();
printf("\n\n\t *************** single check done *********** \n\n");
printf("\n\n\t *************** start multiple test *********** \n");
int * ptrs[10];
printf("\t *************** create trackers ********************\n");
for(; i < 10; i++){
ptrs[i] = malloc(sizeof(int) * 10 * i);
Ptr(&ptrs[i]);
}
printf("\t *************** check trackers ********************\n");
PtrCheck();
printf("\t *************** free pointers but set not NULL *****\n");
for(i--; i > 0; i-- ){ free(ptrs[i]); }
printf("\t *************** check trackers ********************\n");
PtrCheck();
printf("\t *************** set pointers NULL *****************\n");
for(i=0; i < 10; i++){ ptrs[i] = NULL; }
printf("\t *************** check trackers ********************\n");
PtrCheck();
printf("\t *************** free trackers ********************\n");
PtrFree();
printf("\tdone");
return 0;
}
The below code is what I have used once to check if some pointer tries to access illegal memory. The mechanism is to induce a SIGSEGV. The SEGV signal was redirected to a private function earlier, which uses longjmp to get back to the program. It is kind of a hack but it works.
The code can be improved (use 'sigaction' instead of 'signal' etc), but it is just to give an idea. Also it is portable to other Unix versions, for Windows I am not sure. Note that the SIGSEGV signal should not be used somewhere else in your program.
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <signal.h>
jmp_buf jump;
void segv (int sig)
{
longjmp (jump, 1);
}
int memcheck (void *x)
{
volatile char c;
int illegal = 0;
signal (SIGSEGV, segv);
if (!setjmp (jump))
c = *(char *) (x);
else
illegal = 1;
signal (SIGSEGV, SIG_DFL);
return (illegal);
}
int main (int argc, char *argv[])
{
int *i, *j;
i = malloc (1);
if (memcheck (i))
printf ("i points to illegal memory\n");
if (memcheck (j))
printf ("j points to illegal memory\n");
free (i);
return (0);
}