Do not cache hardcoded formats in FormatManager

The cache in FormatCache uses only a type name as key. The hardcoded
formats, synthetic children, etc inspect an entire ValueObject to
determine their eligibility, which isn't modelled in the cache. This
leads to bugs such as the one in this patch (where two similarly named
types in different files have different hardcoded summary
providers). The problem is exaggerated in the Swift language plugin
due to the language's dynamic nature.

rdar://problem/57756763

Differential Revision: https://reviews.llvm.org/D71233
This commit is contained in:
Adrian Prantl 2019-12-09 16:38:19 -08:00
parent 44c167ace9
commit 62a6d97704
6 changed files with 65 additions and 13 deletions

View File

@ -209,7 +209,8 @@ private:
ConstString m_vectortypes_category_name;
template <typename ImplSP>
ImplSP GetCached(ValueObject &valobj, lldb::DynamicValueType use_dynamic);
ImplSP Get(ValueObject &valobj, lldb::DynamicValueType use_dynamic);
template <typename ImplSP> ImplSP GetCached(FormattersMatchData &match_data);
template <typename ImplSP> ImplSP GetHardcoded(FormattersMatchData &);
TypeCategoryMap &GetCategories() { return m_categories_map; }

View File

@ -0,0 +1,3 @@
C_SOURCES := a.c b.c
include Makefile.rules

View File

@ -0,0 +1,27 @@
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
class TestDataFormatterCaching(TestBase):
mydir = TestBase.compute_mydir(__file__)
def setUp(self):
TestBase.setUp(self)
def test_with_run_command(self):
"""
Test that hardcoded summary formatter matches aren't improperly cached.
"""
self.build()
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
self, 'break here', lldb.SBFileSpec('a.c'))
valobj = self.frame().FindVariable('f')
self.assertEqual(valobj.GetValue(), '4')
bkpt_b = target.BreakpointCreateBySourceRegex('break here',
lldb.SBFileSpec('b.c'))
lldbutil.continue_to_breakpoint(process, bkpt_b)
valobj = self.frame().FindVariable('f4')
self.assertEqual(valobj.GetSummary(), '(1, 2, 3, 4)')

View File

@ -0,0 +1,7 @@
typedef float float4;
int main() {
float4 f = 4.0f;
// break here
return a();
}

View File

@ -0,0 +1,8 @@
typedef float float4 __attribute__((ext_vector_type(4)));
void stop() {}
int a() {
float4 f4 = {1, 2, 3, 4};
// break here
stop();
return 0;
}

View File

@ -622,11 +622,21 @@ ImplSP FormatManager::GetHardcoded(FormattersMatchData &match_data) {
return retval_sp;
}
template <typename ImplSP> ImplSP
FormatManager::GetCached(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
ImplSP retval_sp;
template <typename ImplSP>
ImplSP FormatManager::Get(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
FormattersMatchData match_data(valobj, use_dynamic);
if (ImplSP retval_sp = GetCached<ImplSP>(match_data))
return retval_sp;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
LLDB_LOGF(log, "[%s] Search failed. Giving hardcoded a chance.", __FUNCTION__);
return GetHardcoded<ImplSP>(match_data);
}
template <typename ImplSP>
ImplSP FormatManager::GetCached(FormattersMatchData &match_data) {
ImplSP retval_sp;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
if (match_data.GetTypeForCache()) {
LLDB_LOGF(log, "\n\n[%s] Looking into cache for type %s", __FUNCTION__,
@ -659,10 +669,6 @@ FormatManager::GetCached(ValueObject &valobj,
return retval_sp;
}
}
if (!retval_sp) {
LLDB_LOGF(log, "[%s] Search failed. Giving hardcoded a chance.", __FUNCTION__);
retval_sp = GetHardcoded<ImplSP>(match_data);
}
if (match_data.GetTypeForCache() && (!retval_sp || !retval_sp->NonCacheable())) {
LLDB_LOGF(log, "[%s] Caching %p for type %s", __FUNCTION__,
@ -678,25 +684,25 @@ FormatManager::GetCached(ValueObject &valobj,
lldb::TypeFormatImplSP
FormatManager::GetFormat(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
return GetCached<lldb::TypeFormatImplSP>(valobj, use_dynamic);
return Get<lldb::TypeFormatImplSP>(valobj, use_dynamic);
}
lldb::TypeSummaryImplSP
FormatManager::GetSummaryFormat(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
return GetCached<lldb::TypeSummaryImplSP>(valobj, use_dynamic);
return Get<lldb::TypeSummaryImplSP>(valobj, use_dynamic);
}
lldb::SyntheticChildrenSP
FormatManager::GetSyntheticChildren(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
return GetCached<lldb::SyntheticChildrenSP>(valobj, use_dynamic);
return Get<lldb::SyntheticChildrenSP>(valobj, use_dynamic);
}
lldb::TypeValidatorImplSP
FormatManager::GetValidator(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
return GetCached<lldb::TypeValidatorImplSP>(valobj, use_dynamic);
return Get<lldb::TypeValidatorImplSP>(valobj, use_dynamic);
}
FormatManager::FormatManager()