aboutsummaryrefslogtreecommitdiff
path: root/gdb/ada-varobj.c
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@adacore.com>2019-02-10 03:14:53 -0500
committerJoel Brobecker <brobecker@adacore.com>2019-02-10 03:14:53 -0500
commitaff29d1c738c0327e7b40ba9f6885279b75e3eca (patch)
tree5c223d838520a452a6f3afe76cb73972e9264c4e /gdb/ada-varobj.c
parent10a54ace4aad32c78e1be99201d0a9c6efc63450 (diff)
downloadgdb-aff29d1c738c0327e7b40ba9f6885279b75e3eca.zip
gdb-aff29d1c738c0327e7b40ba9f6885279b75e3eca.tar.gz
gdb-aff29d1c738c0327e7b40ba9f6885279b75e3eca.tar.bz2
(Ada) -var-update crash for variable whose type is a reference to changeable
Consider the following variable, which is a string whose value is not known at compile time, because it is the return value from a function call (Get_Name): A : String := Get_Name; If one tries to create a varobj for that variable, everything works as expected: | (gdb) -var-create a * a | ^done,name="a",numchild="19",value="[19] \"Some kind of string\"",type="<ref> array (1 .. 19) of character",thread-id="1",has_more="0" However, try then to request an update, regardless of whether the string has changed or not, and we get a crash: | -var-update a | ~"/[...]/gdb/varobj.c:1379: internal-error: bool install_new_value(varobj*, value*, bool): Assertion `!value_lazy (var->value.get ())' failed.\nA problem internal to GDB has been detected,\nfurther debugging may prove unreliable.\nQuit this debugging session? (y or n) " When the varobj gets created (-var-create), the expression is evaluated and transformed into a value. The debugging information describes our variables as a reference to an array of characters, so our value has the corresponding type. We then call varobj.c::install_new_value to store that value inside our varobj, and we see that this function pretty starts by determining weither our varobj is changeable, via: | changeable = varobj_value_is_changeable_p (var); (where 'var' is the varobj we are building, and where the function varobj_value_is_changeable_p simply dispatches to the Ada version of this routine: ada_value_is_changeable_p). At this point, the varobj doesn't have a value, yet, but it does have a type which was provided by varobj_create a little bit before install_new_value was called. So ada_value_is_changeable_p uses that to determine whether or not our type is changeable. Since our type is a reference to an array, and that the value of such objects is displayed as if there weren't a reference, it means that our object is changeable -- in other words, if an element of the string changes, then the "value" field of the varobj will change accordingly. But unfortunately, ada_value_is_changeable_p mistakenly returns false, because it is missing the handling of reference types. As a consequence of this, install_new_value doesn't feel it is necessary to fetch the value's contents, as explained by the following comment inside that function: /* The new value might be lazy. If the type is changeable, that is we'll be comparing values of this type, fetch the value now. Otherwise, on the next update the old value will be lazy, which means we've lost that old value. */ This means that a lazy value gets installed inside our varobj as a result of the mistake in ada_value_is_changeable_p. Another important detail is that, after determining whether our varobj is changeable or not, it then purposefully removes the reference layer from our value: /* We are not interested in the address of references, and given that in C++ a reference is not rebindable, it cannot meaningfully change. So, get hold of the real value. */ if (value) value = coerce_ref (value); The consequence of those two facts on shows up only later, when the user requests an update (-var-update). When doing so, GDB evaluates the expression again into a value which is once more a reference to a string, and then calls install_new_value again to install the new value and report any changes. This time around, the call to... | changeable = varobj_value_is_changeable_p (var); ... now gets a varobj which has a value, and one which had the reference layer removed! So, this time, we classify the varobj correctly, and say it is changeable. And because it is changeable, we then go into the section of code in install_new_value which checks for changes, where we need the varobj's value to not be lazy, as explained by the comment we quoted above. That's what the assertion was about. This patch fixes the issues by teaching ada_value_is_changeable_p to ignore reference layers when evaluating a given varobj's type. gdb/ChangeLog: * ada-varobj.c (ada_value_is_changeable_p): Add handling of TYPE_CODE_REF types. gdb/testsuite/ChangeLog: * gdb.ada/mi_ref_changeable: New testcase. Prior to this patch, this testcase reports 2 unresolved tests (due to GDB hitting the internal error). With this patch, all tests in this testcase pass. Tested on x86_64-linux, no regression.
Diffstat (limited to 'gdb/ada-varobj.c')
-rw-r--r--gdb/ada-varobj.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
index 3b339e0..a4d553d 100644
--- a/gdb/ada-varobj.c
+++ b/gdb/ada-varobj.c
@@ -935,6 +935,9 @@ ada_value_is_changeable_p (const struct varobj *var)
struct type *type = (var->value != nullptr
? value_type (var->value.get ()) : var->type);
+ if (TYPE_CODE (type) == TYPE_CODE_REF)
+ type = TYPE_TARGET_TYPE (type);
+
if (ada_is_access_to_unconstrained_array (type))
{
/* This is in reality a pointer to an unconstrained array.