Check for allocated memory with a pointer

Is it possible to check if a function pointer is passed to memory or not in C?

I have my own function in C that takes a character pointer - buf [buffer pointer] and size - buf_siz [buffer size]. In fact, before calling this function, the user must create a buffer and allocate its memory buf_siz.

Since there is a possibility that the user may forget to make a memory allocation and just pass a pointer to my function, I want to check this. So is there any way to check my function to see if the passed pointer was actually allocated with buf_siz .. memory size ??

EDIT1: It seems there is no standard library to check this .. but is there any dirty hack to check it .. ??

EDIT2: I know that my function will be used by a good C programmer ... But I want to know if we can check or not. If we can, I would love to hear to him ..

Conclusion: Thus, it is impossible to check whether a specific pointer with memory is allocated or not inside the function

+58
c pointers
Oct. 16 '09 at 5:46
source share
19 answers

You cannot check, except for some specific implementation hacks.

Pointers do not have information with them, except where they indicate. The best you can do is say: "I know how this particular version of the compiler allocates memory, so I will look for memory, move the pointer back 4 bytes, check the size, make sure it matches ..." and so on . You cannot do this in a standard way, since the allocation of memory is determined by the implementation. Not to mention the fact that they may not have dynamically allocated it at all.

You just need to assume that your client knows how to program in C. The only solution I can imagine is to allocate the memory on my own and return it, but this is hardly a small change. (This is a larger design change.)

+25
Oct 16 '09 at 5:48
source share

For a platform-oriented solution, you might be interested in the Win32 IsBadReadPtr function (and the like). This function will be able to (almost) predict whether you will get a segmentation error when reading from a specific piece of memory.

However, this will not protect you in the general case, since the operating system does not know anything about the C runtime manager, and if the caller passes in a buffer that is not as large as you expect, the rest of the heap block will continue to be read from the point of view OS

+8
Oct. 16 '09 at 6:14
source share

Below is the code that I used once to check if any pointer is trying to access illegal memory. The mechanism is to induce SIGSEGV. The SEGV signal was previously redirected to a private function that uses longjmp to return to the program. This is a kind of hack, but it works.

The code can be improved (use 'sigaction' instead of 'signal', etc.), but this is just to give an idea. It also migrates to other versions of Unix, for Windows I'm not sure. Please note that the SIGSEGV signal should not be used anywhere 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); } 
+8
Mar 11 '13 at 13:58 on
source share

I once used a dirty hack on my 64-bit Solaris. In 64-bit mode, the heap starts at 0x1 0000 0000. By comparing the pointer, I could determine if it was a pointer in the data or code segment p < (void*)0x100000000 , a pointer in the heap p > (void*)0x100000000 or a pointer in memory mapping area (intptr_t)p < 0 (mmap returns addresses from the top of the address area). This allowed in my program to keep the pointers highlighted and displayed on the map on one map, and my map module frees the correct pointers.

But this trick is very unmanageable, and if your code relies on something like that, it's time to rethink the architecture of your code. You are probably something wrong.

+6
Dec 23
source share

I always initialize pointers to a null value. Therefore, when I allocate memory, it will change. When I check the memory allocation, I do pointer != NULL . When I free the memory, I also set the pointer to zero. I can not figure out how to determine if there is enough allocated memory.

This does not solve your problem, but you must believe that if someone writes C programs, then he is qualified enough to do it right.

+4
Oct 16 '09 at 6:15
source share

No, there’s no way to do this.

In addition, if your interface simply “pass a pointer to the buffer into which I will put the material”, then the caller may choose not to allocate memory at all, but instead use a fixed-size buffer that is statically assigned or an automatic variable or something. Or maybe it's a pointer to part of a larger object on the heap.

If your interface definitely says "pass a pointer to the allocated memory (because I'm going to free it)", then you should expect the caller to do this. The inability to do this is not something that you can reliably detect.

+2
Oct. 16 '09 at 5:54
source share

One hack you can try is to check if your pointer points to the stack of allocated memory. This will not help you at all, since the allocated buffer may be small or the pointer points to some section of global memory (.bss, .const, ...).

To perform this hack, first save the address of the first variable in main (). Later, you can compare this address with the address of a local variable in your specific procedure. All addresses between both addresses are located on the stack.

+2
Oct. 16 '09 at 7:56
source share

I know this is an old question, but almost everything is possible in C. There are several hacking solutions here, but the correct way to determine if memory is allocated correctly is to use the oracle to replace the place malloc , calloc , realloc and free . Similarly, test environments (e.g. cmocka) can detect memory problems (seg errors, not freeing memory, etc.). You can save the list of memory addresses allocated as they are allocated, and simply check this list when the user wants to use your function. I implemented something very similar for my own testing platform. Code example:

 typedef struct memory_ref { void *ptr; int bytes; memory_ref *next; } memory_ref *HEAD = NULL; void *__wrap_malloc(size_t bytes) { if(HEAD == NULL) { HEAD = __real_malloc(sizeof(memory_ref)); } void *tmpPtr = __real_malloc(bytes); memory_ref *previousRef = HEAD; memory_ref *currentRef = HEAD->next; while(current != NULL) { previousRef = currentRef; currentRef = currentRef->next; } memory_ref *newRef = (memory_ref *)__real_malloc(sizeof(memory_ref)); *newRef = (memory_ref){ .ptr = tmpPtr, .bytes = bytes, .next = NULL }; previousRef->next = newRef; return tmpPtr; } 

You would have similar functions for calloc , realloc and free , each wrapper with the __wrap_ prefix. Real malloc is available using __real_malloc (similarly for other functions that you wrap). Whenever you want to check if memory is actually allocated, simply go to the linked list memory_ref and find the memory address. If you find it large enough, you know for sure that the memory address will not crash your program; otherwise return an error. In the header file that your program uses, you must add the following lines:

 extern void *__real_malloc (size_t); extern void *__wrap_malloc (size_t); extern void *__real_realloc (size_t); extern void *__wrap_realloc (size_t); // Declare all the other functions that will be wrapped... 

My needs were pretty simple, so I implemented a very basic implementation, but you can imagine how it can be expanded to have a better tracking system (for example, create a struct that keeps track of the memory location in addition to size). Then you just compile the code with

 gcc src_files -o dest_file -Wl,-wrap,malloc -Wl,-wrap,calloc -Wl,-wrap,realloc -Wl,-wrap,free 

The disadvantage is that the user must compile the source code with the above directives; however, this is far from worse than what I saw. There is some overhead for allocating and freeing memory, but when adding security, there is always some overhead.

+2
Apr 25 '16 at 0:29
source share

You cannot test anything available in standard C. Even if your specific compiler had to provide a function for this, it would still be a bad idea. Here is an example of why:

 int YourFunc(char * buf, int buf_size); char str[COUNT]; result = YourFunc(str, COUNT); 
+1
Oct. 16 '09 at 5:52
source share

Like everyone else, there is no standard way to do this.

So far, no one has mentioned Steve Maguire's "Writing Solid Code" . Despite the fact that in some quarters , the book has chapters on memory management, it discusses how with caution and complete control over memory allocation in a program you can do as you ask and determine if the pointer you pointed to is a valid pointer to dynamically allocated memory, however, if you plan to use third-party libraries, you will find that few of them allow you to change the allocation procedures memory allocations on their own, which greatly complicates such an analysis.

+1
Oct 16 '09 at 6:21
source share

I do not know how to do this from a library call, but on Linux you can see /proc/<pid>/numa_maps . It will display all sections of memory, and the heap or pile will be indicated in the third column. You can look at the value of the raw pointer to see where it is.

Example:

 00400000 prefer:0 file=/usr/bin/bash mapped=163 mapmax=9 N0=3 N1=160 006dc000 prefer:0 file=/usr/bin/bash anon=1 dirty=1 N0=1 006dd000 prefer:0 file=/usr/bin/bash anon=9 dirty=9 N0=3 N1=6 006e6000 prefer:0 anon=6 dirty=6 N0=2 N1=4 01167000 prefer:0 heap anon=122 dirty=122 N0=25 N1=97 7f39904d2000 prefer:0 anon=1 dirty=1 N0=1 7f39904d3000 prefer:0 file=/usr/lib64/ld-2.17.so anon=1 dirty=1 N0=1 7f39904d4000 prefer:0 file=/usr/lib64/ld-2.17.so anon=1 dirty=1 N1=1 7f39904d5000 prefer:0 anon=1 dirty=1 N0=1 7fffc2d6a000 prefer:0 stack anon=6 dirty=6 N0=3 N1=3 7fffc2dfe000 prefer:0 

Thus, pointers located above 0x01167000 but below 0x7f39904d2000 are located on the heap.

+1
Mar 15 '16 at 10:40
source share

No, you can’t. You will notice that no functions in the standard library or anywhere else are executed. This is because there is no standard way to tell. The calling code simply has to take responsibility for the proper management of the memory.

0
Oct. 16 '09 at 5:53
source share

In general, lib users are responsible for input validation and validation. You can see ASSERT or something in the lib code, and they are used only for debugging. This is the standard way to write C / C ++. while many coders like to do this verification and shipyards in their lib code very carefully. really “BAD” habits. As stated in IOP / IOD, lib interfaces must be contracted and explain what lib does and what does not, and what the lib user should do and what is not needed.

0
16 Oct '09 at 8:08
source share

An uninitialized pointer is exactly like that - uninitialized. It can point to something or just be an invalid address (i.e. Do not display in physical or virtual memory).

A practical solution is to have a valid signature in the specified objects. Create a malloc () wrapper that highlights the requested block size plus the size of the signature structure, creates a signature structure at the beginning of the block, but returns a pointer to the location after the signature. You can then create a validation function that takes a pointer, uses a negative bias to get a validity structure, and validates it. Of course, you will need the appropriate free () wrapper to invalidate this block by replacing the validity signature and freeing it from the true start of the selected block.

As a confidence structure, you can use the size of the block and its one complement. Thus, you have not only a way to check the block (XOR two values ​​and a comparison with zero), but also information about the size of the block.

0
Oct. 16 '09 at 8:47
source share

There is an easy 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 it allocates memory using your function e.g.

 struct struct_type struct_var = init_struct_type() 

if this struct_var contains dynamically allocated memory, e.g.

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; } 

That way, if it does not assign the value temp-> string to the value, it will remain NULL. You can test functions that use this structure if the string is NULL or not.

One more thing, if a programmer is so bad that he cannot use your functions, but rather accesses unallocated memory, he does not deserve to use your library. Just make sure everything is listed in your documentation.

0
Dec 23
source share

You can, by calling malloc_size(my_ptr) in malloc/malloc.h , returns the malloc size allocated for you for your pointer, and 0 if the pointer was not selected. Keep in mind that malloc resizes the allocated block to ensure that the most restrictive type variable can be dereferenced from this pointer and align memory. Therefore, if you call malloc (1) (as well as malloc (0)), malloc actually returns 16 bytes (on most machines), because the most restrictive type is 16 bytes in size.

0
Dec 16 '16 at 0:06
source share

Tracks a pointer, tracks and verifies that the pointer is correct

using:

create memory int * ptr = malloc (sizeof (int) * 10);

add the address of the pointer to the Ptr tracker (& ptr);

check for error 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 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 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; } 
0
Aug 14 '17 at 18:32
source share

In computers, almost never "never". A cross platform is the path expected. After 25 years, I worked on hundreds of projects awaiting a cross-platform, and it never materialized.

Obviously, the variable on the stack indicates an area on the stack that is almost linear. Cross-platform garbage collectors work by marking the top or bottom of the stack, calling a small function to check if the stack is growing up or down, and then checking the stack pointer to know how big the stack is. This is your range. I do not know a machine that does not implement the stack in this way (grow or fall).

You just check if the address of our object or pointer is between the top and bottom of the stack. Here's how you know if this is a stack variable.

Too easy. Hey, is this C ++ right? No. Is this important right? After 25 years, I saw a more accurate assessment of correctness. Well, let's say this: if you hack, you are not doing real programming, you are probably just updating what has already been done.

How interesting is that?

-one
Apr 13 2018-12-12T00:
source share

Well, I don’t know if someone did not post it here or it will be possible in your program. I struggled with a similar thing in my university project.

I solved it quite simply - in the initialization part of main (), after I declared LIST *ptr , I just put it ptr=NULL . Like this -

 int main(int argc, char **argv) { LIST *ptr; ptr=NULL; 

Thus, when the distribution fails or your pointer is not highlighted at all, it will be NULL. So you can just check it out if.

 if (ptr==NULL) { "THE LIST DOESN'T EXIST" } else { "THE LIST MUST EXIST --> SO IT HAS BEEN ALLOCATED" } 

I don't know how your program is written, but you probably understand what I'm trying to point out. If it is possible to verify your distribution in this way, and then pass your arguments to the function, you may have a simple solution.

Of course, you have to be careful that your distribution and structure functions do well, but in C you don't have to be careful.

-one
Jan 16 '19 at 16:44
source share



All Articles