From 4d0754c5f572b01cf2fe6c8ab292adba83331cbc Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 30 Jul 2021 11:18:36 -0600 Subject: [PATCH] Avoid crash in varobj deletion PR varobj/28131 points out a crash in the varobj deletion code. It took a while to reproduce this, but essentially what happens is that a top-level varobj deletes its root object, then deletes the "dynamic" object. However, deletion of the dynamic object may cause ~py_varobj_iter to run, which in turn uses gdbpy_enter_varobj: gdbpy_enter_varobj::gdbpy_enter_varobj (const struct varobj *var) : gdbpy_enter (var->root->exp->gdbarch, var->root->exp->language_defn) { } However, because var->root has already been destroyed, this is invalid. I've added a new test case. This doesn't reliably crash, but the problem can easily be seen under valgrind (and, I presume, with ASAN, though I did not try this). Tested on x86-64 Fedora 32. I also propose putting this on the GDB 11 branch, with a suitable ChangeLog entry of course. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28131 --- .../gdb.python/py-mi-var-info-path-expression.exp | 12 ++++++++++++ gdb/varobj.c | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp b/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp index 2688851dbcc..4328c599321 100644 --- a/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp +++ b/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp @@ -85,3 +85,15 @@ mi_gdb_test "-var-list-children c1.car.atom" \ mi_gdb_test "-var-info-path-expression c1.car.atom.ival" \ "\\^error,msg=\".*\"" \ "-var-info-path-expression c1.car.atom.ival" + + +# Regression test for a crasher that would occur when deleting a +# varobj that held an iterator that hadn't yet been completed. +# See PR varobj/28131. +mi_gdb_test "-var-create c1_again * &c1" \ + "\\^done.*" \ + "-var-create c1_again * &c1" +mi_gdb_test "-var-list-children c1_again 0 1" \ + "\\^done,numchild=\"1\",children=.child=\{name=\"c1_again.car\".*" \ + "-var-list-children c1_again" +mi_delete_varobj c1_again "delete c1_again" diff --git a/gdb/varobj.c b/gdb/varobj.c index 7928d90bef3..d0c857a6906 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -1844,10 +1844,12 @@ varobj::~varobj () } #endif + /* This must be deleted before the root object, because Python-based + destructors need access to some components. */ + delete var->dynamic; + if (is_root_p (var)) delete var->root; - - delete var->dynamic; } /* Return the type of the value that's stored in VAR, -- 2.30.2