mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-09-19 19:19:05 +01:00
remove treebuilder pointer validation
This commit is contained in:
parent
28025fa416
commit
cd2fa8c9ef
@ -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)) {
|
||||||
|
StoreData(1, returnArg);
|
||||||
getSizeType(*(s_ptr), returnArg);
|
getSizeType(*(s_ptr), returnArg);
|
||||||
|
} else {
|
||||||
|
StoreData(0, returnArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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>
|
||||||
|
@ -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>();
|
||||||
|
@ -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 = '''
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -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)) {
|
||||||
|
SAVE_DATA(1);
|
||||||
getSizeType(*head, returnArg);
|
getSizeType(*head, returnArg);
|
||||||
|
} else {
|
||||||
|
SAVE_DATA(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -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()));
|
||||||
|
if (pointers.add((uintptr_t)&ref.get())) {
|
||||||
|
SAVE_DATA(1);
|
||||||
getSizeType(ref.get(), returnArg);
|
getSizeType(ref.get(), returnArg);
|
||||||
|
} else {
|
||||||
|
SAVE_DATA(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -24,7 +24,10 @@ void getSizeType(const %1%<T> &s_ptr, size_t& returnArg)
|
|||||||
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()))) {
|
||||||
|
SAVE_DATA(1);
|
||||||
getSizeType(*(s_ptr.get()), returnArg);
|
getSizeType(*(s_ptr.get()), returnArg);
|
||||||
|
} else {
|
||||||
|
SAVE_DATA(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,10 @@ void getSizeType(const %1%<T,Deleter> &s_ptr, size_t& returnArg)
|
|||||||
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()))) {
|
||||||
|
SAVE_DATA(1);
|
||||||
getSizeType(*(s_ptr.get()), returnArg);
|
getSizeType(*(s_ptr.get()), returnArg);
|
||||||
|
} else {
|
||||||
|
SAVE_DATA(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user