Bug 21381

Summary: Invalid -var-info-path-expression result with anonymous union in std::string
Product: gdb Reporter: Simon Marchi <simark>
Component: varobjAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal CC: malaperle, tromey
Priority: P2    
Version: HEAD   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: proposed patch

Description Simon Marchi 2017-04-12 20:49:14 UTC
This is rather specific, but it's probably possible to create a smaller test case.

Test source:

---- 8< ----
#include <string>

int
main ()
{
  std::string s;
  s = "foo";

  return 0;
}
---- >8 ----

compilation line: g++ test.cpp -g3 -O0 -o test
gdb command line: gdb -i mi -nx test

MI commands used:

start
-var-create - * s
-var-list-children var1
-var-list-children var1.private
-var-list-children var1.private.2_anonymous
-var-list-children var1.private.2_anonymous.public
-var-list-children var1.private.2_anonymous.public._M_local_buf

So far everything is fine, it just creates all the variable object children.  Now we try to use -var-info-path-expression on the last one:

-var-info-path-expression var1.private.2_anonymous.public._M_local_buf
^done,path_expr="(()._M_local_buf)"

The returned expression is not valid.  It should have been "((s)._M_local_buf)".
Comment 1 Simon Marchi 2017-04-12 20:51:19 UTC
Versions used:
GNU gdb (GDB) 7.12.50.20170121-git
gcc (GCC) 6.3.1 20170306
Comment 2 Simon Marchi 2017-04-14 19:29:06 UTC
Created attachment 9994 [details]
proposed patch
Comment 3 Simon Marchi 2017-04-14 19:43:36 UTC
I think I identified the problem.  In c_is_path_expr_parent, we are doing this:

field_name = TYPE_FIELD_NAME (parent_type, var->index);

var->index is the index of the current varobj (a class field) in its parent.  The problem is that the varobj index in its parent doesn't translate directly to an index in the array of fields of the type of its parent, which is assumed by the statement above.

That's because while the fields array of the class type looks like this:

[0] public field npos
[1] private field _M_dataplus
[2] private field _M_string_length
[3] private field <anonymous union>

... the varobj tree looks like:

string
  public
    npos
  private
    _M_dataplus
    _M_string_length
    2_anonymous (name given to the anonymous union by gdb)

When calling c_is_path_expr_parent with var = 2_anonymous, var->index is 2 (it's the index in its varobj parent).  This index is used to lookup the field type in the parent's type's field table, which erroneously ends up referring to _M_string_length.  It returns true instead of false, which ends up in an empty string being used as a path instead of searching higher in the varobj tree for something that really is a path expression parent.

So, like in cplus_describe_child, we have to iterate on the parent's type's field table to find the 3rd private field (as in the proposed patch).  That will find the right field.

In cplus_describe_child, we could probably assert that parent_expression is not empty.
Comment 4 Marc-Andre Laperle 2017-04-17 16:38:49 UTC
(In reply to Simon Marchi from comment #2)
> Created attachment 9994 [details]
> proposed patch

I tested it and the patch seems to work!
Comment 5 Tom Tromey 2023-08-31 17:26:48 UTC
This access stuff is terrible (see bug #10683).
But meanwhile, what's up with this patch?