<rdar://problem/13623698>

This patch fixes the issue that we were using the C stack as a measure of depth of ValueObject hierarchies, in the sense that we were assuming that recursive ValueObject operations would never be deeper than the stack allows.
This assumption is easy to prove wrong, however.
For instance, after ~10k runs through this loop:
struct node
{
	int value;
	node* child;
	node (int x)
	{
		value = x;
		child = nullptr;
	}
};

int main ()
{
	node root(1);
	node* ptr = &root;
	int j = 2;
	while (1)
	{
		ptr->child = new node(j++);
		ptr = ptr->child;
	}
	return 0;
}

the deepmost child object will be deeper than the stack on most architectures, and we would be unable to display it

This checkin fixes the issue by introducing a notion of root of ValueObject hierarchies.
In a couple cases, we have to use an iterative algorithm instead of going to the root because we want to allow deeper customizations (e.g. formats, dynamic values).
While the patch passes our test suite without regressions, it is a good idea to keep eyes open for any unexpected behavior (recursion can be subtle..)
Also, I am hesitant to introduce a test case since failing at this will not just be marked as an "F", but most definitely crash LLDB.

llvm-svn: 179330
This commit is contained in:
Enrico Granata 2013-04-11 22:48:58 +00:00
parent 3342b9b2c9
commit 4873e52733
4 changed files with 99 additions and 33 deletions

View File

@ -738,12 +738,10 @@ public:
// value is from an executable file and might have its data in // value is from an executable file and might have its data in
// sections of the file. This can be used for variables. // sections of the file. This can be used for variables.
virtual lldb::ModuleSP virtual lldb::ModuleSP
GetModule() GetModule();
{
if (m_parent) virtual ValueObject*
return m_parent->GetModule(); GetRoot ();
return lldb::ModuleSP();
}
virtual bool virtual bool
GetDeclaration (Declaration &decl); GetDeclaration (Declaration &decl);
@ -876,14 +874,8 @@ public:
virtual lldb::ValueObjectSP virtual lldb::ValueObjectSP
GetDynamicValue (lldb::DynamicValueType valueType); GetDynamicValue (lldb::DynamicValueType valueType);
virtual lldb::DynamicValueType lldb::DynamicValueType
GetDynamicValueType () GetDynamicValueType ();
{
if (m_parent)
return m_parent->GetDynamicValueType ();
else
return lldb::eNoDynamicValues;
}
virtual lldb::ValueObjectSP virtual lldb::ValueObjectSP
GetStaticValue (); GetStaticValue ();
@ -1020,12 +1012,7 @@ public:
} }
lldb::Format lldb::Format
GetFormat () const GetFormat () const;
{
if (m_parent && m_format == lldb::eFormatDefault)
return m_parent->GetFormat();
return m_format;
}
void void
SetFormat (lldb::Format format) SetFormat (lldb::Format format)
@ -1104,15 +1091,7 @@ public:
} }
AddressType AddressType
GetAddressTypeOfChildren() GetAddressTypeOfChildren();
{
if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid)
{
if (m_parent)
return m_parent->GetAddressTypeOfChildren();
}
return m_address_type_of_ptr_or_ref_children;
}
void void
SetHasCompleteType() SetHasCompleteType()
@ -1213,6 +1192,7 @@ protected:
// Classes that inherit from ValueObject can see and modify these // Classes that inherit from ValueObject can see and modify these
//------------------------------------------------------------------ //------------------------------------------------------------------
ValueObject * m_parent; // The parent value object, or NULL if this has no parent ValueObject * m_parent; // The parent value object, or NULL if this has no parent
ValueObject * m_root; // The root of the hierarchy for this ValueObject (or NULL if never calculated)
EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
// updated. When we are asked to update the value object, we check whether // updated. When we are asked to update the value object, we check whether
// the context & stop id are the same before updating. // the context & stop id are the same before updating.
@ -1300,6 +1280,18 @@ protected:
virtual void virtual void
CalculateDynamicValue (lldb::DynamicValueType use_dynamic); CalculateDynamicValue (lldb::DynamicValueType use_dynamic);
virtual lldb::DynamicValueType
GetDynamicValueTypeImpl ()
{
return lldb::eNoDynamicValues;
}
virtual bool
HasDynamicValueTypeInfo ()
{
return false;
}
virtual void virtual void
CalculateSyntheticValue (bool use_synthetic = true); CalculateSyntheticValue (bool use_synthetic = true);

View File

@ -90,15 +90,21 @@ public:
virtual bool virtual bool
SetValueFromCString (const char *value_str, Error& error); SetValueFromCString (const char *value_str, Error& error);
protected:
virtual bool
UpdateValue ();
virtual lldb::DynamicValueType virtual lldb::DynamicValueType
GetDynamicValueType () GetDynamicValueTypeImpl ()
{ {
return m_use_dynamic; return m_use_dynamic;
} }
protected:
virtual bool virtual bool
UpdateValue (); HasDynamicValueTypeInfo ()
{
return true;
}
virtual clang::ASTContext * virtual clang::ASTContext *
GetClangASTImpl (); GetClangASTImpl ();

View File

@ -64,6 +64,7 @@ static user_id_t g_value_obj_uid = 0;
ValueObject::ValueObject (ValueObject &parent) : ValueObject::ValueObject (ValueObject &parent) :
UserID (++g_value_obj_uid), // Unique identifier for every value object UserID (++g_value_obj_uid), // Unique identifier for every value object
m_parent (&parent), m_parent (&parent),
m_root (NULL),
m_update_point (parent.GetUpdatePoint ()), m_update_point (parent.GetUpdatePoint ()),
m_name (), m_name (),
m_data (), m_data (),
@ -108,6 +109,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
AddressType child_ptr_or_ref_addr_type) : AddressType child_ptr_or_ref_addr_type) :
UserID (++g_value_obj_uid), // Unique identifier for every value object UserID (++g_value_obj_uid), // Unique identifier for every value object
m_parent (NULL), m_parent (NULL),
m_root (NULL),
m_update_point (exe_scope), m_update_point (exe_scope),
m_name (), m_name (),
m_data (), m_data (),
@ -4150,3 +4152,66 @@ ValueObject::CreateValueObjectFromData (const char* name,
new_value_sp->SetName(ConstString(name)); new_value_sp->SetName(ConstString(name));
return new_value_sp; return new_value_sp;
} }
ModuleSP
ValueObject::GetModule ()
{
ValueObject* root(GetRoot());
if (root != this)
return root->GetModule();
return lldb::ModuleSP();
}
ValueObject*
ValueObject::GetRoot ()
{
if (m_root)
return m_root;
ValueObject* parent = m_parent;
if (!parent)
return (m_root = this);
while (parent->m_parent)
{
if (parent->m_root)
return (m_root = parent->m_root);
parent = parent->m_parent;
}
return (m_root = parent);
}
AddressType
ValueObject::GetAddressTypeOfChildren()
{
if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid)
{
ValueObject* root(GetRoot());
if (root != this)
return root->GetAddressTypeOfChildren();
}
return m_address_type_of_ptr_or_ref_children;
}
lldb::DynamicValueType
ValueObject::GetDynamicValueType ()
{
ValueObject* with_dv_info = this;
while (with_dv_info)
{
if (with_dv_info->HasDynamicValueTypeInfo())
return with_dv_info->GetDynamicValueTypeImpl();
with_dv_info = with_dv_info->m_parent;
}
return lldb::eNoDynamicValues;
}
lldb::Format
ValueObject::GetFormat () const
{
const ValueObject* with_fmt_info = this;
while (with_fmt_info)
{
if (with_fmt_info->m_format != lldb::eFormatDefault)
return with_fmt_info->m_format;
with_fmt_info = with_fmt_info->m_parent;
}
return m_format;
}

View File

@ -229,5 +229,8 @@ ValueObjectChild::UpdateValue ()
bool bool
ValueObjectChild::IsInScope () ValueObjectChild::IsInScope ()
{ {
return m_parent->IsInScope (); ValueObject* root(GetRoot());
if (root)
return root->IsInScope ();
return false;
} }