remove treebuilder pointer validation

This commit is contained in:
Jake Hillion 2023-04-05 12:55:40 -07:00 committed by Jake Hillion
parent 28025fa416
commit cd2fa8c9ef
10 changed files with 71 additions and 54 deletions

View File

@ -3284,7 +3284,10 @@ bool OICodeGen::generateJitCode(std::string& code) {
JLOGPTR(s_ptr); JLOGPTR(s_ptr);
StoreData((uintptr_t)(s_ptr), returnArg); StoreData((uintptr_t)(s_ptr), returnArg);
if (s_ptr && pointers.add((uintptr_t)s_ptr)) { if (s_ptr && pointers.add((uintptr_t)s_ptr)) {
getSizeType(*(s_ptr), returnArg); StoreData(1, returnArg);
getSizeType(*(s_ptr), returnArg);
} else {
StoreData(0, returnArg);
} }
} }

View File

@ -39,6 +39,17 @@ extern "C" {
#include <sys/types.h> #include <sys/types.h>
} }
/* Tag indicating if the pointer has been followed or skipped */
enum class TrackPointerTag: uint64_t {
/* The content has been skipped.
* It prevents double counting the footprint of a node the JIT code has seen
* before, double counting content being stored inline, or getting stuck in an
* infinite loop when processing circular linked list.
*/
skipped = 0,
followed = 1,
};
TreeBuilder::TreeBuilder(Config c) : config{std::move(c)} { TreeBuilder::TreeBuilder(Config c) : config{std::move(c)} {
buffer = std::make_unique<msgpack::sbuffer>(); buffer = std::make_unique<msgpack::sbuffer>();
@ -205,7 +216,6 @@ void TreeBuilder::build(const std::vector<uint64_t>& data,
th = &typeHierarchy; th = &typeHierarchy;
oidData = &data; oidData = &data;
pointers.clear();
oidDataIndex = 3; // HACK: OID's first 3 outputs are dummy 0s oidDataIndex = 3; // HACK: OID's first 3 outputs are dummy 0s
ObjectIntrospection::Metrics::Tracing _("build_tree"); ObjectIntrospection::Metrics::Tracing _("build_tree");
@ -215,8 +225,9 @@ void TreeBuilder::build(const std::vector<uint64_t>& data,
auto& rootID = rootIDs.emplace_back(nextNodeID++); auto& rootID = rootIDs.emplace_back(nextNodeID++);
try { try {
// The first value is the address of the root object // The first value is the address of the root object. Drop it as we don't
pointers.insert(next()); // need to manage pointer deduplication anymore.
next();
process(rootID, {.type = type, .name = argName, .typePath = argName}); process(rootID, {.type = type, .name = argName, .typePath = argName});
} catch (...) { } catch (...) {
// Mark the failure using the error node ID // Mark the failure using the error node ID
@ -367,15 +378,6 @@ bool TreeBuilder::isPrimitive(struct drgn_type* type) {
return drgn_type_primitive(type) != DRGN_NOT_PRIMITIVE_TYPE; return drgn_type_primitive(type) != DRGN_NOT_PRIMITIVE_TYPE;
} }
bool TreeBuilder::shouldProcess(uintptr_t pointer) {
if (pointer == 0U) {
return false;
}
auto [_, unprocessed] = pointers.emplace(pointer);
return unprocessed;
}
static std::string_view drgnKindStr(struct drgn_type* type) { static std::string_view drgnKindStr(struct drgn_type* type) {
auto kind = OICodeGen::drgnKindStr(type); auto kind = OICodeGen::drgnKindStr(type);
// -1 is for the null terminator // -1 is for the null terminator
@ -427,8 +429,10 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
auto innerTypeKind = drgn_type_kind(entry->second); auto innerTypeKind = drgn_type_kind(entry->second);
if (innerTypeKind != DRGN_TYPE_FUNCTION) { if (innerTypeKind != DRGN_TYPE_FUNCTION) {
node.pointer = next(); node.pointer = next();
if (innerTypeKind == DRGN_TYPE_VOID || if (innerTypeKind == DRGN_TYPE_VOID) {
!shouldProcess(*node.pointer)) { break;
}
if (next() == (uint64_t)TrackPointerTag::skipped) {
break; break;
} }
} }
@ -626,7 +630,7 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
node.pointer = next(); node.pointer = next();
containerStats.length = *node.pointer ? 1 : 0; containerStats.length = *node.pointer ? 1 : 0;
containerStats.capacity = 1; containerStats.capacity = 1;
if (!shouldProcess(*node.pointer)) { if (next() == (uint64_t)TrackPointerTag::skipped) {
return; return;
} }
break; break;
@ -634,7 +638,7 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
case REF_WRAPPER_TYPE: case REF_WRAPPER_TYPE:
node.pointer = next(); node.pointer = next();
containerStats.length = containerStats.capacity = 1; containerStats.length = containerStats.capacity = 1;
if (!shouldProcess(*node.pointer)) { if (next() == (uint64_t)TrackPointerTag::skipped) {
return; return;
} }
break; break;
@ -723,7 +727,7 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
case FOLLY_IOBUFQUEUE_TYPE: case FOLLY_IOBUFQUEUE_TYPE:
node.pointer = next(); node.pointer = next();
containerStats.length = containerStats.capacity = 0; containerStats.length = containerStats.capacity = 0;
if (!shouldProcess(*node.pointer)) { if (next() == (uint64_t)TrackPointerTag::skipped) {
return; return;
} }
// Fallthrough to the IOBuf data if we have a valid pointer // Fallthrough to the IOBuf data if we have a valid pointer
@ -736,20 +740,17 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
node.pointer = next(); node.pointer = next();
containerStats.capacity = next(); containerStats.capacity = next();
containerStats.length = next(); containerStats.length = next();
// If this string's data is potentially shared (cutoff for sharing is 255) // Contents are either stored inline or have been seen before in the JIT
if (containerStats.capacity >= 255) { // code. Set to true either way so as not to double count.
// Contents aren't actually stored inline in this case, contentsStoredInline = next() == 0;
// but we set this to `true` so that we don't double-count
// this string's data if we have seen it before. {
contentsStoredInline = !shouldProcess(*node.pointer); constexpr int sharedCutOff = 255;
} else { if (containerStats.capacity < sharedCutOff) {
// No sense in recording the pointer value if the string isn't // No sense in recording the pointer value if the string isn't
// potentially shared // potentially shared.
node.pointer.reset(); node.pointer.reset();
// Account for Small String Optimization (SSO) }
const int fbStringSsoCutOff = 23;
constexpr size_t ssoCutoff = fbStringSsoCutOff;
contentsStoredInline = containerStats.capacity <= ssoCutoff;
} }
break; break;
case STRING_TYPE: case STRING_TYPE:

View File

@ -99,13 +99,11 @@ class TreeBuilder {
*/ */
std::unique_ptr<msgpack::sbuffer> buffer; std::unique_ptr<msgpack::sbuffer> buffer;
rocksdb::DB* db = nullptr; rocksdb::DB* db = nullptr;
std::unordered_set<uintptr_t> pointers{};
uint64_t getDrgnTypeSize(struct drgn_type* type); uint64_t getDrgnTypeSize(struct drgn_type* type);
uint64_t next(); uint64_t next();
bool isContainer(const Variable& variable); bool isContainer(const Variable& variable);
bool isPrimitive(struct drgn_type* type); bool isPrimitive(struct drgn_type* type);
bool shouldProcess(uintptr_t pointer);
Node process(NodeID id, Variable variable); Node process(NodeID id, Variable variable);
void processContainer(const Variable& variable, Node& node); void processContainer(const Variable& variable, Node& node);
template <class T> template <class T>

View File

@ -90,7 +90,6 @@ definitions = '''
''' '''
[cases.unique_ptr] [cases.unique_ptr]
oil_skip = "OIL processes one node in the cycle twice" # https://github.com/facebookexperimental/object-introspection/issues/104
param_types = ["std::reference_wrapper<UniqueNode>&"] param_types = ["std::reference_wrapper<UniqueNode>&"]
setup = ''' setup = '''
auto first = std::make_unique<UniqueNode>(); auto first = std::make_unique<UniqueNode>();
@ -168,7 +167,6 @@ definitions = '''
''' '''
[cases.shared_ptr] [cases.shared_ptr]
oil_skip = "OIL processes one node in the cycle twice" # https://github.com/facebookexperimental/object-introspection/issues/104
param_types = ["std::reference_wrapper<SharedNode>&"] param_types = ["std::reference_wrapper<SharedNode>&"]
setup = ''' setup = '''
auto first = std::make_shared<SharedNode>(); auto first = std::make_shared<SharedNode>();

View File

@ -76,7 +76,6 @@ includes = ["folly/FBString.h"]
''' '''
[cases.string_pooled] [cases.string_pooled]
skip = "Potentially incorrect dynamic size"
param_types = ["folly::fbstring&"] param_types = ["folly::fbstring&"]
setup = "return folly::fbstring(1024, 'c');" setup = "return folly::fbstring(1024, 'c');"
expect_json = ''' expect_json = '''

View File

@ -24,12 +24,15 @@ void getSizeType(const %1%<E, T, A, Storage> &t, size_t& returnArg)
SAVE_DATA((uintptr_t)t.capacity()); SAVE_DATA((uintptr_t)t.capacity());
SAVE_DATA((uintptr_t)t.size()); SAVE_DATA((uintptr_t)t.size());
// Check if the string is contained within the type (inlined) so as not to double count. bool inlined = ((uintptr_t)t.data() < (uintptr_t)(&t + sizeof(%1%<E, T, A, Storage>)))
SAVE_SIZE(
((uintptr_t)t.data() < (uintptr_t)(&t + sizeof(%1%<E, T, A, Storage>)))
&& &&
((uintptr_t)t.data() >= (uintptr_t)&t) ((uintptr_t)t.data() >= (uintptr_t)&t);
? 0 : (t.capacity() * sizeof(T))
); if (!inlined && pointers.add((uintptr_t)t.data())) {
SAVE_SIZE(t.capacity() * sizeof(T));
SAVE_DATA(1);
} else {
SAVE_DATA(0);
}
} }
""" """

View File

@ -21,7 +21,11 @@ void getSizeType(const %1% &t, size_t& returnArg)
const IOBuf *head = t.front(); const IOBuf *head = t.front();
SAVE_DATA((uintptr_t)head); SAVE_DATA((uintptr_t)head);
if (head) if (head && pointers.add((uintptr_t)head)) {
getSizeType(*head, returnArg); SAVE_DATA(1);
getSizeType(*head, returnArg);
} else {
SAVE_DATA(0);
}
} }
""" """

View File

@ -20,6 +20,11 @@ void getSizeType(const %1%<T> &ref, size_t& returnArg)
{ {
SAVE_SIZE(sizeof(%1%<T>)); SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)&(ref.get())); SAVE_DATA((uintptr_t)&(ref.get()));
getSizeType(ref.get(), returnArg); if (pointers.add((uintptr_t)&ref.get())) {
SAVE_DATA(1);
getSizeType(ref.get(), returnArg);
} else {
SAVE_DATA(0);
}
} }
""" """

View File

@ -21,11 +21,14 @@ void getSizeType(const %1%<T> &s_ptr, size_t& returnArg)
SAVE_SIZE(sizeof(%1%<T>)); SAVE_SIZE(sizeof(%1%<T>));
if constexpr (!std::is_void<T>::value) { if constexpr (!std::is_void<T>::value) {
SAVE_DATA((uintptr_t)(s_ptr.get())); SAVE_DATA((uintptr_t)(s_ptr.get()));
if (s_ptr && pointers.add((uintptr_t)(s_ptr.get()))) { if (s_ptr && pointers.add((uintptr_t)(s_ptr.get()))) {
getSizeType(*(s_ptr.get()), returnArg); SAVE_DATA(1);
} getSizeType(*(s_ptr.get()), returnArg);
} else {
SAVE_DATA(0);
}
} }
} }
""" """

View File

@ -21,11 +21,14 @@ void getSizeType(const %1%<T,Deleter> &s_ptr, size_t& returnArg)
SAVE_SIZE(sizeof(%1%<T,Deleter>)); SAVE_SIZE(sizeof(%1%<T,Deleter>));
if constexpr (!std::is_void<T>::value) { if constexpr (!std::is_void<T>::value) {
SAVE_DATA((uintptr_t)(s_ptr.get())); SAVE_DATA((uintptr_t)(s_ptr.get()));
if (s_ptr && pointers.add((uintptr_t)(s_ptr.get()))) { if (s_ptr && pointers.add((uintptr_t)(s_ptr.get()))) {
getSizeType(*(s_ptr.get()), returnArg); SAVE_DATA(1);
} getSizeType(*(s_ptr.get()), returnArg);
} else {
SAVE_DATA(0);
}
} }
} }
""" """