Navigation Menu

Skip to content

Commit

Permalink
Prevent GetNumChildren from transitively walking pointer chains
Browse files Browse the repository at this point in the history
Summary:

This is an attempt to fix https://bugs.llvm.org/show_bug.cgi?id=45988,
where SBValue::GetNumChildren returns 2, but SBValue::GetChildAtIndex(1) returns
an invalid value sentinel.

The root cause of this seems to be that GetNumChildren can return the number of
children of a wrong value. In particular, for pointers GetNumChildren just
recursively calls itself on the pointee type, so it effectively walks chains of
pointers. This is different from the logic of GetChildAtIndex, which only
recurses if pointee.IsAggregateType() returns true (IsAggregateType is false for
pointers and references), so it never follows chain of pointers.

This patch aims to make GetNumChildren (more) consistent with GetChildAtIndex by
only recursively calling GetNumChildren for aggregate types.

Ideally, GetNumChildren and GetChildAtIndex would share the code that decides
which pointers/references are followed, but that is a bit more invasive change.

Reviewers: teemperor, jingham, clayborg

Reviewed By: teemperor, clayborg

Subscribers: clayborg, labath, shafik, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D80254
  • Loading branch information
Jaroslav Sevcik authored and Teemperor committed May 25, 2020
1 parent 72c5ea1 commit 83bd2c4
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 21 deletions.
34 changes: 13 additions & 21 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Expand Up @@ -5172,12 +5172,15 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
}
break;

case clang::Type::LValueReference:
case clang::Type::RValueReference:
case clang::Type::ObjCObjectPointer: {
const clang::ObjCObjectPointerType *pointer_type =
llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr());
clang::QualType pointee_type = pointer_type->getPointeeType();
uint32_t num_pointee_children =
GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
CompilerType pointee_clang_type(GetPointeeType(type));

uint32_t num_pointee_children = 0;
if (pointee_clang_type.IsAggregateType())
num_pointee_children =
pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
// If this type points to a simple type, then it has 1 child
if (num_pointee_children == 0)
num_children = 1;
Expand Down Expand Up @@ -5209,8 +5212,11 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
const clang::PointerType *pointer_type =
llvm::cast<clang::PointerType>(qual_type.getTypePtr());
clang::QualType pointee_type(pointer_type->getPointeeType());
uint32_t num_pointee_children =
GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
CompilerType pointee_clang_type(GetType(pointee_type));
uint32_t num_pointee_children = 0;
if (pointee_clang_type.IsAggregateType())
num_pointee_children =
pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx);
if (num_pointee_children == 0) {
// We have a pointer to a pointee type that claims it has no children. We
// will want to look at
Expand All @@ -5219,20 +5225,6 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
num_children = num_pointee_children;
} break;

case clang::Type::LValueReference:
case clang::Type::RValueReference: {
const clang::ReferenceType *reference_type =
llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
clang::QualType pointee_type = reference_type->getPointeeType();
uint32_t num_pointee_children =
GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
// If this type points to a simple type, then it has 1 child
if (num_pointee_children == 0)
num_children = 1;
else
num_children = num_pointee_children;
} break;

default:
break;
}
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/functionalities/pointer_num_children/Makefile
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
@@ -0,0 +1,28 @@
"""
Test children counts of pointer values.
"""

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestPointerNumChilden(TestBase):
mydir = TestBase.compute_mydir(__file__)

def test_pointer_num_children(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp"))

result = self.frame().FindVariable("Ref")
self.assertEqual(1, result.GetNumChildren())
self.assertEqual(2, result.GetChildAtIndex(0).GetNumChildren())
self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
self.assertEqual("56", result.GetChildAtIndex(0).GetChildAtIndex(1).GetValue())

result = self.frame().FindVariable("Ptr")
self.assertEqual(1, result.GetNumChildren())
self.assertEqual(2, result.GetChildAtIndex(0).GetNumChildren())
self.assertEqual("42", result.GetChildAtIndex(0).GetChildAtIndex(0).GetValue())
self.assertEqual("56", result.GetChildAtIndex(0).GetChildAtIndex(1).GetValue())
16 changes: 16 additions & 0 deletions lldb/test/API/functionalities/pointer_num_children/main.cpp
@@ -0,0 +1,16 @@
struct Inner {
int a;
int b;
};

struct Outer {
Inner *inner;
};

int main() {
Inner inner{42, 56};
Outer outer{&inner};
Inner **Ptr = &(outer.inner);
Inner *&Ref = outer.inner;
return 0; // break here
}

0 comments on commit 83bd2c4

Please sign in to comment.