I just realised today that I forgot to query gdb for a backtrace. Doing so now reveals the following:
(gdb) bt
#0 0x00007f86db992060 in NodePath::find_common_ancestor(NodePath const&, NodePath const&, int&, int&, Thread*) ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#1 0x00007f86db9a25ca in NodePath::get_transform(NodePath const&, Thread*) const ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#2 0x00007f86dbb2fd97 in CollisionEntry::get_wrt_mat() const ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#3 0x00007f86dbb45a8a in CollisionPolygon::test_intersection_from_line(CollisionEntry const&) const ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#4 0x00007f86dbb2fe22 in CollisionLine::test_intersection(CollisionEntry const&) const ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#5 0x00007f86dbb30cb0 in ?? ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#6 0x00007f86dbb37db4 in CollisionTraverser::compare_collider_to_node(Collision--Type <RET> for more, q to quit, c to continue without paging--
Entry&, GeometricBoundingVolume const*, GeometricBoundingVolume const*, GeometricBoundingVolume const*) ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#7 0x00007f86dbb4f680 in ?? ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#8 0x00007f86dbb4efa0 in ?? ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#9 0x00007f86dbb51753 in CollisionTraverser::traverse(NodePath const&) ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#10 0x00007f86dcc672d5 in ?? ()
from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/panda3d.core.so
#11 0x00000000004de3cd in ?? ()
#12 0x000000000042468e in _PyEval_EvalFrameDefault ()
#13 0x000000000058ca94 in ?? ()
#14 0x000000000042468e in _PyEval_EvalFrameDefault ()
#15 0x000000000058ca94 in ?? ()
#16 0x000000000042468e in _PyEval_EvalFrameDefault ()
#17 0x000000000058ca94 in ?? ()
--Type <RET> for more, q to quit, c to continue without paging--c
#18 0x000000000042468e in _PyEval_EvalFrameDefault ()
#19 0x000000000058ca94 in ?? ()
#20 0x000000000042468e in _PyEval_EvalFrameDefault ()
#21 0x000000000058ca94 in ?? ()
#22 0x00000000004267e0 in _PyEval_EvalFrameDefault ()
#23 0x000000000058ca94 in ?? ()
#24 0x00000000004267e0 in _PyEval_EvalFrameDefault ()
#25 0x000000000058ca94 in ?? ()
#26 0x000000000042468e in _PyEval_EvalFrameDefault ()
#27 0x000000000058ca94 in ?? ()
#28 0x00000000004d755b in ?? ()
#29 0x00007f86dcfea765 in ?? () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/panda3d.core.so
#30 0x00007f86dcff0417 in ?? () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/panda3d.core.so
#31 0x00007f86dcff0df9 in ?? () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/panda3d.core.so
#32 0x00007f86dbbc1749 in AsyncTask::unlock_and_do_task() () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#33 0x00007f86dbbcb1ca in AsyncTaskChain::service_one_task(AsyncTaskChain::AsyncTaskChainThread*) () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#34 0x00007f86dbbcb5df in AsyncTaskChain::do_poll() () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#35 0x00007f86dbbcbb58 in AsyncTaskManager::poll() () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/libpanda.so.1.10
#36 0x00007f86dccce7c3 in ?? () from /home/thaumaturge/Desktop/mew/Moons in Crystal-0.7.5_manylinux2014_x86_64/Moons in Crystal/panda3d.core.so
#37 0x00000000004df00b in ?? ()
#38 0x000000000042468e in _PyEval_EvalFrameDefault ()
#39 0x000000000058ca94 in ?? ()
#40 0x000000000042468e in _PyEval_EvalFrameDefault ()
#41 0x000000000058ca94 in ?? ()
#42 0x000000000042468e in _PyEval_EvalFrameDefault ()
#43 0x000000000058ca94 in ?? ()
#44 0x000000000042468e in _PyEval_EvalFrameDefault ()
#45 0x000000000058ca94 in ?? ()
#46 0x000000000058cc4b in PyEval_EvalCode ()
#47 0x000000000042bf16 in ?? ()
#48 0x000000000042d592 in PyImport_ImportFrozenModuleObject ()
#49 0x000000000042d7cc in PyImport_ImportFrozenModule ()
#50 0x0000000000427ed0 in Py_FrozenMain ()
#51 0x000000000041d92a in ?? ()
#52 0x00007f86ddff9d90 in __libc_start_call_main (main=main@entry=0x41d740, argc=argc@entry=1, argv=argv@entry=0x7ffe5d9f0918) at ../sysdeps/nptl/libc_start_call_main.h:58
#53 0x00007f86ddff9e40 in __libc_start_main_impl (main=0x41d740, argc=1, argv=0x7ffe5d9f0918, init=<optimised out>, fini=<optimised out>, rtld_fini=<optimised out>, stack_end=0x7ffe5d9f0908) at ../csu/libc-start.c:392
#54 0x0000000000427ad5 in _start ()
So, it looks like the crash is occurring due to some action of the traversal system.
Of interest is that it appears to involve the CollisionLine class–and I’m using that in only two places, both within the same class and for the same essential purpose.
(That being to detect which room an object or point lies within, which is achieved by colliding a vertical CollisionLine against the CollisionPolygons that represent the room’s floorplan.)
Now, that still may be in some way related to my repopulating the world with enemies.
That said, the actual traversals performed by the class that is presumably using these CollisionLines should not be threaded, and the collision-objects are managed by that class.
However, it does occur to me that the method that sets up the collision-objects may well be called from within a thread. (As it’s done as part of object-spawning.)
Could it be that, if the timing is just wrong, and a collision-object is added during traversal, that causes the crash? Maybe due to the object not yet being fully set up or attached, or some such…?
(Also, with the new information recently discovered I’ve tried again to create a game-state that reliably reproduces the crash–thus far to no avail.)
If it _is_related to thread-prompted addition of a collision-object during traversal, can anyone think of a way to create a reliable test-program for that…?
(I mean, creating a program that adds collision-objects in a thread is easy enough, I daresay–it’s getting their addition to coincide with non-threaded traversal that I’m uncertain about…)
[edit]
Okay, I think that I’ve created a test-program that reliably segfaults in a manner that at least seems similar to what I’m observing in my main program.
The exact method in which the segfault occurs varies from run to run–but then I’ve only seen a stack trace for a single crash in my main program, and so don’t know whether it varies there, too. That said, I have seen it occur within “find_common_ancestor”–or, in this case, a method called by that method.
The test-program is as follows:
from panda3d.core import loadPrcFile, loadPrcFileData
loadPrcFileData("", "show-frame-rate-meter #t")
loadPrcFileData("", "frame-rate-meter-milliseconds #t")
from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionNode, CollisionLine, CollisionTraverser, CollisionHandlerQueue, BitMask32
from direct.stdpy import threading
from panda3d import __version__ as pandaVersion
print (pandaVersion)
import sys
print (sys.version)
class TestThread(threading.Thread):
def __init__(self, game):
threading.Thread.__init__(self)
self.game = game
def run(self):
print ("Running")
while (self.game.runThread):
if self.game.line is None:
self.game.addLine()
else:
self.game.removeLine()
class Game(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.generalTraverser = CollisionTraverser()
self.line = None
self.queue = None
self.taskMgr.add(self.update, "update")
self.testThread = TestThread(self)
self.testThread.start()
self.accept("space", self.stopThread)
self.runThread = True
def stopThread(self):
self.runThread = False
def update(self, task):
self.generalTraverser.traverse(render)
if self.queue is not None:
print (self.queue.getNumEntries())
return task.cont
def addLine(self):
ray = CollisionLine(0, 0, 0, 0, 0, -1)
rayNode = CollisionNode("room detector")
rayNode.addSolid(ray)
rayNode.setIntoCollideMask(0)
mask = BitMask32(1)
rayNode.setFromCollideMask(mask)
rayNP = render.attachNewNode(rayNode)
queue = CollisionHandlerQueue()
self.generalTraverser.addCollider(rayNP, queue)
self.line = rayNP
self.queue = queue
#print ("Adding line")
def removeLine(self):
if self.line is not None:
self.line.removeNode()
self.generalTraverser.removeCollider(self.line)
self.line = None
if self.queue is not None:
self.queue = None
#print ("Removing line")
app = Game()
app.run()