Thread: Determining if an address is pointing to dynamically allocated memory or not

  1. #1
    Registered User
    Join Date
    Oct 2015
    Posts
    11

    Determining if an address is pointing to dynamically allocated memory or not

    Hi everyone !

    Lastly, I've looked for a way of determining wether a pointer points to some dynamically allocated memory, or global or automatic variables. And that without simply registering all allocations and checking each time if the pointer is an allocation, which is obviously extremely inefficient. The reason I've been looking for that kind of thing is also pretty obvious, for example, testing a pointer to know if it needs to be freed or not, or anything alike.

    And all that, because nowadays, everyone and me first tend to allocate pretty much everything dynamically, which is fine up to some point. As a matter of fact, there are many things that could simply be declared instead of allocated, for instance, a list of all available extensions to some program could be declared statically, or at least, it's header. Anyway.

    So this morning I thought of something that works, and is surprisingly simple. For a given pointer, given the layout of a process (at least a Linux process), you just need to compare it to the address of the break before you do any allocation (which you can obtain using sbrk (0), which is declared in <unistd.h>), and also to the address of the stack, which (at least on Linux) grows downward from the highest virtual memory address.

    I don't actually have a very particular question, I would just like to have your opinion on wether it is good or bad practice, if there are situations in which it wouldn't work, this kind of things. It obviously isn't really portable, because the layout of a process changes accross operating systems, but it is usually similar and concceptually equivalent, so adapting the code isn't really complicated. Here is the code, by the way :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <unistd.h>
    
    void *my_break = NULL;
    extern unsigned int IsStatic (void *ptr);
    
    static unsigned int initialize (void);
    static unsigned int finalize (void *ptr, ...);
    
    unsigned int global_static = 0;
    unsigned int *global_dynamic = NULL;
    
    static unsigned int initialize (void) {
        my_break = sbrk (0);
        return 0;
    }
    
    static unsigned int finalize (void *ptr, ...) {
        va_list arguments;
        void *current = NULL;
    
        va_start (arguments, ptr);
        for (current = ptr; current != NULL; current = va_arg (arguments, void *))
            free (current);
        va_end (arguments);
    }
    
    
    int main (int argc, char *argv []) {
        unsigned int ret = 0;
        ret = initialize ();
        if (ret) return finalize (NULL);
    
        global_static = 17;
        global_dynamic = calloc (1, sizeof (unsigned int));
        if (global_dynamic == NULL) return finalize (NULL);
        *global_dynamic = 34;
    
        unsigned int local_static = 18;
        unsigned int *local_dynamic = NULL;
        local_dynamic = calloc (1, sizeof (unsigned int));
        if (local_dynamic == NULL) return finalize (global_dynamic, NULL);
    
        printf ("global_static: %d\n", IsStatic (&global_static));
        printf ("global_dynamic: %d\n", IsStatic (global_dynamic));
        printf ("local_static: %d\n", IsStatic (&local_static));
        printf ("local_dynamic: %d\n", IsStatic (local_dynamic));
    
        ret = finalize (global_dynamic, local_dynamic, NULL);
        return ret;
    }
    And because I don't like inline assembly, and because the function to determine if an address is static or not mostly does things you can only do in assembly, I wrote it directly in assembly, nothing really complicated anyway. Notice it uses System V 64 bits calling convention, which is nearly standard accross Unix-like operating systems.

    Code:
        [BITS 64]
        SECTION .text
        GLOBAL IsStatic
        EXTERN my_break
    
    IsStatic:
        push rbp
        mov rbp, rsp
        push rdi
        mov rax, [my_break]
        cmp rdi, rax
        jge .L01
        mov rax, 0
        jmp .L_end
    .L01:
        cmp rdi, rsp
        jbe .L02
        mov rax, 0
        jmp .L_end
    .L02:
        mov rax, 1
    .L_end:
        pop rdi
        mov rsp, rbp
        pop rbp
        ret
    Oh and it's for NASM. Just in case, here's how you compile :
    Code:
    $ nasm -felf64 isstatic.asm
    $ gcc -o main main.c isstatic.o
    And again, it works, but tell me what you think of it

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,149
    I am curious if it is valuable in practice: how would you use it as part of a garbage collector?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2015
    Posts
    11
    I suppose you can just pass any pointer to the garbage collector without worrying about them to be dynamically allocated or not, it won't cause what in specifications is called "undefined behavior", which in pratice usually means segmentation fault. For example, if a list containing a mix of static and dynamic memory pointers, and you obviously don't remember which is which, well, you don't need to care anymore

  4. #4
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    You can do it without the assembly and sbrk.

    You should store the addresses as void*, not unsigned int.

    I don't think the first malloc is guaranteed to extend the program break. It's possible there's enough extra space already allocated.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    void *dynamic_bottom;
    int global;
    
    int is_dynamic(void *a) {  // &a is the top of the stack
        return a >= dynamic_bottom && a < (void*)&a;
    }
    
    int main(void) {
        dynamic_bottom = malloc(1);
    
        int *dynamic = malloc(sizeof(int));
        int local;
    
        printf("global:  %d\n", is_dynamic(&global));
        printf("local:   %d\n", is_dynamic(&local));
        printf("dynamic: %d\n", is_dynamic(dynamic));
    
        return 0;
    }

  5. #5
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Quote Originally Posted by levenstein View Post
    And because I don't like inline assembly, and because the function to determine if an address is static or not mostly does things you can only do in assembly, I wrote it directly in assembly, nothing really complicated anyway. ...

    Code:
        [BITS 64]
        SECTION .text
        GLOBAL IsStatic
        EXTERN my_break
    
    IsStatic:
        push rbp
        mov rbp, rsp
        push rdi
        mov rax, [my_break]
        cmp rdi, rax
        jge .L01
        mov rax, 0
        jmp .L_end
    .L01:
        cmp rdi, rsp
        jbe .L02
        mov rax, 0
        jmp .L_end
    .L02:
        mov rax, 1
    .L_end:
        pop rdi
        mov rsp, rbp
        pop rbp
        ret
    ...And again, it works, but tell me what you think of it
    Is there a specific reason you didn't just write this directly as the following:

    Code:
    int IsStatic(void *ptr) {
        if (ptr >= my_break) return 0;
        else return 1;
    }

  6. #6
    Registered User
    Join Date
    Oct 2015
    Posts
    11
    I guess this could work most of the time, but though I'm not a specialist of memory allocators, I think it is possible some weird thing happens and gives you a bad result for dynamic_bottom.

  7. #7
    Registered User
    Join Date
    Oct 2015
    Posts
    11
    The thing is, c99tutorial, you don't test for the address to belong to the call stack ; in which case it must be considered as a static variable too, which is not quite true, but at least it's not dynamically allocated and you do not need to free it. So in assembly, you just can get the stack pointer and make the comparison.

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    Quote Originally Posted by levenstein View Post
    I guess this could work most of the time, but though I'm not a specialist of memory allocators, I think it is possible some weird thing happens and gives you a bad result for dynamic_bottom.
    I demonstrated how your use of assembly was completely unnecessary, but you don't thank me for that. Instead you criticize my improvement of your sbrk method while admitting to a total lack of knowledge. You're an idiot.

  9. #9
    Registered User
    Join Date
    Oct 2015
    Posts
    11
    You know, I usually don't waste my time with people like you, but whatever, I don't get ........ed off for so little, it's actually quite some fun, and I'm on holiday anyway. You apparently think that being an .............. like Sherlock Holmes makes you as clever as Sherlock Holmes, in which case I fear you are as unreal as Sherlock Holmes. You know, because, it's a persona, in a book. In the real world, people usually show respect and dignity, two concepts that sadly seem to lack in your social skills. Especially when you are in front, not actually in front, but let's say in front of people you do not know across the Internet ; admitting, of course, you are in a place where you can expect to come across worthy and respectful people, which is certainly not most of the Internet but fortunately is the case here. It's a programming forum, right, not a weapon-selling website or something like that.
    The thing is you might be speaking to a physicist, a software engineer or simply a hobbyist, or a plethora of other people, but in all cases it doesn't make any difference. You might be speaking to some very clever people, and that even in ways you are probably very far from being able to understand.

    That's why the statement "You're an idiot" is almost as meaningless as "I demonstrated", because in both cases, you didn't actually demonstrated anything ; you just, based on the very few previous lines of text and code I shared, built an internal representation of who I could be, and in such a way you could throw some anger and narcissism against it. Wonderful chemistry, that of the brain, isn't it ? A few molecules of adrenalin (though I believe in English-speaking countries, it is rather called epinephrine), and everything becomes irritating.
    Maybe is there a need to remind you that a demonstration relies on facts linked by logical statements ; let's put aside "You're an idiot", that's forgivable because of that wonderful brain chemistry. But the demonstration of the uselessness of assembly, well, can't be put aside, would it only be for the sole fact it doesn't exist. You just wrote "You can do it without the assembly", which only is a demonstration in Aristotle's terms, so it isn't. Using assembly actually is justified, for a few reasons, mainly being that I wanted to, it's never a bad exercise, and that your solution doesn't work in the case of a function without any argument. Though it could still have to deal with static pointers, let's say, registered in some global list. In addition, moving to threaded environments, it can become much more subtle and that very quickly, where in the assembly you are always sure of using the stack pointer.

    The lesson is, in the end, you don't read what people write, you read what you want to, which makes quite a difference. What you call admitting my lack of knowledge was in fact what is called modesty, which I believe is also absent from you social skills so on that point you can be forgiven too. I actually have studied memory allocators among quite a few things, but I don't especially like throwing my knowledge on the table, in apparently a remarkably intense contrast to you. And more important, though I have studied them, it doesn't prevent me from being wrong somewhere, for forgetting something, and in general, to question my judgment. That's the scientific mind, because effectively, I'm a physicist and programmed computers long before I could do Newton mechanics. But why mention ?

    Had you written nicely and gently, I would've thanked, so simply, so easily, and nobody would be edgy here. And there is only you who are. But again. If you don't read what is written, it's useless, but it doesn't matter, I had fun writing it. Still, hopefully, you'll be a better person after that.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Freeing dynamically allocated memory
    By kkk in forum C Programming
    Replies: 4
    Last Post: 05-30-2011, 12:24 PM
  2. Replies: 29
    Last Post: 07-25-2010, 04:36 PM
  3. Dynamically allocated memory question
    By caduardo21 in forum C Programming
    Replies: 3
    Last Post: 01-13-2006, 07:37 PM
  4. Dynamically allocated memory
    By ^xor in forum Linux Programming
    Replies: 9
    Last Post: 06-28-2005, 11:42 AM
  5. Checking if memory has been dynamically allocated
    By Xzyx987X in forum C Programming
    Replies: 28
    Last Post: 03-14-2004, 06:53 PM

Tags for this Thread