4

I was wondering is there any way to create a dangling pointers in python? I guess we have to manually delete an object for example and then the reference of that object will point at a location that has no meaning for the program. I found this example Here

import weakref
class Object:
    pass

o = Object()    #new instance
print ("o id is:",id(o))
r = weakref.ref(o)
print ("r id is:",id(r))
o2 = r()
print ("o2 id is:",id(o2))
print ("r() id is:",id(r()))
print (o is o2)         

del o,o2
print (r(),r)   #If the referent no longer exists, calling the reference object returns None

o = r()         # r is a weak reference object
if o is None:
    # referent has been garbage collected
    print ("Object has been deallocated; can't frobnicate.")
else:
    print ("Object is still live!")
    o.do_something_useful()

In this example which one is the dangling pointer/reference? Is it o or r? I am confused. Is it also possible to create dangling pointers in stack? If you please, give me some simple examples so i can understand how it goes. Thanks in advance.

3 Answers 3

4

All Python objects live on the heap. The stack is only used for function calls.

Calling a weakref object dereferences it and gives you a strong reference to the object, if the object is still around. Otherwise, you get None. In the latter case, you might call the weakref "dangling" (r in your example).

However, Python does not have any notion of a "dangling pointer" in the same way that C does. It's not possible (barring a bug in Python, a buggy extension module or misuse of a module like ctypes) to create a name (strong reference) that refers to a deleted object, because by definition strong references keep their referents alive. On the other hand, weak references are not really dangling pointers, since they are automatically resolved to None if their referents are deleted.

Note that with ctypes abuse it is possible to create a "real" dangling pointer:

import ctypes
a = (1, 2, 3)
ctypes.pythonapi.Py_DecRef(ctypes.py_object(a))
print a

What happens when you print a is now undefined. It might crash the interpreter, print (1, 2, 3), print other tuples, or execute a random function. Of course, this is only possible because you abused ctypes; it's not something that you should ever do.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the answer but i have to make sure that my example is correct. Is it o or r a dangling ref?
r, but really, it's not a dangling reference in the same way that C pointers can dangle.
yes i understand now but its what can be closer to describe it as dangling :) thx
For fun I ran this code on my machine recently, and got the following surprising output: <refcnt 0 at 0x102aaf140>. It seems that the Python interpreter does have some internal checks around zero reference counts, but of course this is very weak (the memory is already freed and could be reallocated any time). Running print a again afterwards curiously printed out an infinite number of ( characters before segfaulting. (Of course, this is all due to a very specific set of circumstances, but I did find it interesting).
2

Barring a bug in Python or an extension, there is no way to refer to a deallocated object. Weak references refer to the object as long as it is alive, while not contributing to keeping it alive. The moment the object is deallocated, the weak reference evaluates to None, so you never get the dangling object. (Even the callback of the weak reference is called after the object has already been deallocated and the weakref dereferences to None, so you cannot resurrect it, either.)

If you could refer to a real deallocated object, Python would most likely crash on first access, because the memory previously held by the object would be reused and the object's type and other slots would contain garbage. Python objects are never allocated on the stack.

If you have a use case why you need to make use of a dangling object, you should present the use case in the form of a question.

5 Comments

Do you consider ctypes an extension?
ctypes is an extension in the Python sense, but that doesn't answer the implied question of whether its ability to create a dangling pointer (or crash Python in a myriad other ways) constitutes a "bug in Python"—or whether it invalidates my initial claim. I would say that the ability to do that is not a bug, as ctypes is intentionally unsafe, but doing it almost certainly is.
ctypes is an advanced and inherently unsafe tool for the oldest of "adults". It is shipped with Python to enable hacks that would otherwise be impossible, but it was never intended that it invalidate the fundamental trait of any good Python implementation that segfaulting the interpreter is, virtually by definition, a bug.
gc is another module which makes it possible to do rather unsafe things. See Lib/test/crashers.
Good point. Note that these crashers are in theory considered bugs, although some of them are hard to fix and some will never be fixed because fixing them brings overall more harm than benefit. According to the readme, "Ideally this directory should always be empty". That cannot be said of ctypes crashes.
1

If you create a weak reference, it becomes "dangling" when the referenced object is deleted (when it's reference count reaches zero, or is part of a closed cycle of objects not referenced by anything else). This is possible because weakref doesn't increase the reference count itself (that's the whole point of a weak reference).

When this happens, everytime you try to "dereference" the weakref object (call it), it returns None.

It is important to remember that in Python variables are actually names, pointing at objects. They are actually "strong references". Example:

import weakref

class A:
    pass

# a new object is created, and the name "x" is set to reference the object,
# giving a reference count of 1
x = A() 

# a weak reference is created referencing the object that the name x references
# the reference count is still 1 though, because x is still the only strong
# reference
weak_reference = weakref.ref(x)

# the only strong reference to the object is deleted (x), reducing the reference
# count to 0 this means that the object is destroyed, and at this point
# "weak_reference" becomes dangling, and calls return None
del x

assert weak_reference() is None

2 Comments

Nice answer. So in the example that i wrote which one is dangled? r or o ?
Neither. In your example, r's reference to o would have become dangling, but Python immediately removes that reference as soon as o is deallocated. In other words, Python does not allow you to create a real dangling reference - see my answer for details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.