C++ - Check if pointer is pointing to valid memory (Can't use NULL checks here)

后端 未结 6 1354
名媛妹妹
名媛妹妹 2020-12-21 18:01

I am creating scripting language. When I allocate thing ,it\'s allocate the thing and returns the address and then I do whatever with it and then delete it. I can\'t contro

相关标签:
6条回答
  • 2020-12-21 18:35

    The simplest solution is to use a map. The map should be indexed by a pointer to the object, likely as a void *. The contents of the map item should be the type of object created.

    Any time a script creates an object, add an entry to the map. Any time a script deletes an object, remove the map entry. When a script accesses an object, find the pointer in the map, thus confirming both that it exists and that the type is correct.

    0 讨论(0)
  • 2020-12-21 18:36

    You can use shared_ptr<> to hold your pointer, and use weak_ptr<> to pass your pointer around to consumers of the object. You delete the object by destroying the shared_ptr<> object, and then all the weak_ptr<>s will become expired.

    std::weak_ptr<int> wptr;
    assert(wptr.expired());
    {
        std::shared_ptr<int> intptr(new int);
        wptr = intptr;
        assert(!wptr.expired());
    }
    assert(wptr.expired());
    

    So, your exists check would be to check if the weak_ptr<> is expired or not.

    To make the usage of the construct a little more concrete:

    Script code                 Hypothetical C++ code that gets executed
    ----                        ----
    var MyVar=new MyStruct();   var_map["MyVar"]
                                    = std::shared_ptr<Obj>(new Obj("MyStruct"));
    Func(MyVar);                invoke("Func", std::weak_ptr<Obj>(var_map["MyVar"]));
    exists(arg0)                !args[0].expired()
    delete(MyVar);              var_map.erase("MyVar");
    

    If the script is to operate in a multi-threaded environment, then the weak_ptr<> state is a critical section.

    0 讨论(0)
  • 2020-12-21 18:36

    This valid check checked in windows only (VS),here is the function:

    #pragma once
    //ptrvalid.h
    __inline bool isValid(void* ptr) {
        if (((uint)ptr)&7==7)
            return false; //Not valid address at all (Maybe random pointer?)
        char _prefix;
        __try {
            _prefix=*(((char*)ptr)-1); //Get the prefix of this data
        } __except (true) { //Catch all unique exceptions (Windows exceptions) 
            return false; //Can't reach this memory
        }
        switch (_prefix) {
        case 0:    //Running release mode with debugger
        case -128: //Running release mode without debugger
        case -2:   //Running debug mode with debugger
        case -35:  //Running debug mode without debugger
            return false; //Deleted :(
            break;
        }
        return true; //Still alive!
    }
    

    Usage:

    #include <stdio.h>
    #include "ptrvalid.h"
    
    void PrintValid(void* ptr) {
        if (isValid(ptr))
            printf("%d is valid.\n",ptr);
        else
            printf("%d is not valid.\n",ptr);
    }
    
    int main() {
        int* my_array=(int*)malloc(4);
        PrintValid(my_array);
        PrintValid((void*)99);
        free(my_array);
        PrintValid(my_array);
        my_array=new int[4];
        PrintValid(my_array);
        delete my_array;
        PrintValid(my_array);
        getchar();
    }
    

    Output:

    764776 is valid.
    99 is not valid.
    764776 is not valid.
    774648 is valid.
    774648 is not valid.
    

    Function's explanation: (What it does)

    The functions check before the real checking ,if the address is valid\start point to memory. After that he checks if this process can reach this memory's prefix (If caught exception if can't) and the last checking is checking what the prefix of this memory if deleted at any mode. (Debugging\Without Debug Mode\Release Mode) If the function passed all of those checks ,it returns true.

    0 讨论(0)
  • 2020-12-21 18:45

    One thing you could do is use your own allocator, in which you can allocate all your objects. Your exists function would simply query the allocator to see if the object is still allocated. Yo could use something similar to SMR to make sure your reference doesn't point to something else while still in use...

    0 讨论(0)
  • 2020-12-21 18:48

    Detecting whether memory no longer is alive could be done e.g. by maintaining a set of known dead pointer. Any pointer you create gets added to an alive set, and when you delete the object you move the pointer to the dead set.

    The really tricky part will be reusing memory. What do you do when you want to reuse the same address for a different object? You can't tell by looking at the pointer, because the pointers look the same. So unless you never want to reuse memory, you'll have to change your requirements.

    1. One possible way would be an added field in the structure. I know you said you don't want that, but many comments already suggest this as the best solution, and I tend to concur.
    2. Another possible way would be an added layer of indirection, so that you don't really pass out pointers to objects but instead indices into a list of living objects or whatever.
    3. You might also consider reference counting and garbage collection. That way objects would only get deleted when no one refers to them any more. Quite a lot of work, but as a user of a scripting languages I'd expect it to provide garbage collection.
    0 讨论(0)
  • 2020-12-21 18:55

    This is a really bad idea. Whether a pointer is safe to use is based on more than just the value of the pointer, it's based on the entire history of the pointer. For instance, let's say that you allocate some memory, then deallocate it but you keep the pointer to it. This pointer is now invalid. Now something else gets allocated to the memory where the previous pointer is. Now if you try to detect if the old pointer is valid, it appears that it is, because the memory it points to is allocated, but if you try to use it, you get undefined behavior. If you read from it, you'll get garbage. If you try to write to it you'll probably corrupt the heap.

    If all you want to do is detect is whether your process can access the memory that the pointer points to, that is possible but not portable, and definitely not a good idea (it will also be very slow). You basically have try to read from or write to it, and then catch the OS exception or signal that results. As I said, even this is a really bad idea. All it tells you is whether the OS will kill your process if you try to access it; not whether it's actually safe to use.

    For more on why this is a bad idea, check out these blog posts from Raymond Chen, who works on some low-level stuff Windows stuff:

    IsBadXxxPtr should really be called CrashProgramRandomly

    There's no point improving the implementation of a bad idea

    0 讨论(0)
提交回复
热议问题