Python interpreter crashes with Datagram / DatagramIterator

Somebody may want to know this. The following code crashes the python interpreter (Python.exe has encountered a problem, etc.):

from panda3d.core import Datagram, DatagramIterator

s = 'This is a message.'

#Doing it this way works:
#dg = Datagram(s)
#dgi = DatagramIterator(dg)

#Doing it this way causes the crash:
dgi = DatagramIterator(Datagram(s))

print dgi
print dgi.getDatagram().getMessage()    #This line crashes.

The output is:

It’s quite easy to work around, but something frightening is happening in the bowels of the Panda3D engine.

Actually, the frightening thing is that Panda is exposing you to some of the foibles of C++. In particular, pointer ownership becomes (to some degree) your responsibility.

What’s happening is that in this line:

dgi = DatagramIterator(Datagram(s))

You are creating a temporary Datagram object, and passing the address of that temporary object to the DatagramIterator constructor, which saves the object’s pointer. But, because this is actually a C++ class that behaves by C++ rules instead of Python rules, the fact that it saved the pointer is not sufficient to keep the temporary Datagram object from being destructed. Sure enough, when the command completes, the temporary Datagram object is destructed by the Python interpreter, and its memory is repurposed. Now the DatagramIterator doesn’t know this happened, and still has the address you gave it, which is no longer valid.

Now when you do this:

print dgi.getDatagram().getMessage()

You are accessing the invalid pointer, which causes a hard crash.

Many of the Panda objects that are exposed to Python are designed to inherit from ReferenceCount, which emulates Python’s reference-counting behavior and protects you from having to know about all this. But certain low-level objects, like Datagram (and a few others) do not inherit from ReferenceCount for performance reasons, and require you to know that you’re responsible for keeping the object around for the lifetime of all references to it.



I see.

That would seem to explain another problem I’m having: I’m creating a DatagramIterator from a Datagram. Then the function returns the DatagramIterator and the Datagram goes out of scope. Now the only thing I don’t understand is that this doesn’t crash Python. It just gives me a DatagramIterator with zero bytes in it. Well, it’ll be easy to work around, now.

Thank you much.

Whenever you have an object go out of scope while you’re still holding a pointer to it, you have a smoking gun. It’s not guaranteed to crash, but it’s not guaranteed not to either. It’s really just unpredictable.


Why do we need to have such things exposed to python then?

You mean things like Vec3?