diff --git a/src/Val.cc b/src/Val.cc index 052e7d0ee7..47d992f564 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1322,12 +1322,12 @@ ValPtr ListVal::DoClone(CloneState* state) return lv; } -unsigned int ListVal::Footprint() const +unsigned int ListVal::Footprint(std::set* analyzed_records) const { unsigned int fp = vals.size(); for ( const auto& val : vals ) - fp += val->Footprint(); + fp += val->Footprint(analyzed_records); return fp; } @@ -2683,7 +2683,7 @@ ValPtr TableVal::DoClone(CloneState* state) return tv; } -unsigned int TableVal::Footprint() const +unsigned int TableVal::Footprint(std::set* analyzed_records) const { unsigned int fp = table_val->Length(); @@ -2693,9 +2693,9 @@ unsigned int TableVal::Footprint() const auto vl = table_hash->RecoverVals(*k); auto v = iter.GetValue()->GetVal(); - fp += vl->Footprint(); + fp += vl->Footprint(analyzed_records); if ( v ) - fp += v->Footprint(); + fp += v->Footprint(analyzed_records); } return fp; @@ -3066,18 +3066,13 @@ ValPtr RecordVal::DoClone(CloneState* state) return rv; } -unsigned int RecordVal::Footprint() const +unsigned int RecordVal::Footprint(std::set* analyzed_records) const { - // Which records we're in the process of analyzing - used to - // avoid infinite recursion for circular types (which can only - // occur due to the presence of records). - static std::unordered_set pending_records; - - if ( pending_records.count(this) > 0 ) + if ( analyzed_records->count(this) > 0 ) // Footprint is 1 for the RecordVal itself. return 1; - pending_records.insert(this); + analyzed_records->insert(this); int n = NumFields(); unsigned int fp = n; @@ -3089,10 +3084,10 @@ unsigned int RecordVal::Footprint() const auto f_i = GetField(i); if ( f_i ) - fp += f_i->Footprint(); + fp += f_i->Footprint(analyzed_records); } - pending_records.erase(this); + analyzed_records->erase(this); return fp; } @@ -3620,7 +3615,7 @@ bool VectorVal::Concretize(const TypePtr& t) return true; } -unsigned int VectorVal::Footprint() const +unsigned int VectorVal::Footprint(std::set* analyzed_records) const { auto n = vector_val->size(); unsigned int fp = n; @@ -3629,7 +3624,7 @@ unsigned int VectorVal::Footprint() const { auto v = At(i); if ( v ) - fp += v->Footprint(); + fp += v->Footprint(analyzed_records); } return fp; diff --git a/src/Val.h b/src/Val.h index d3c605022b..d0075f7259 100644 --- a/src/Val.h +++ b/src/Val.h @@ -127,9 +127,13 @@ public: * The number is not meant to be precise, but rather comparable: * larger footprint correlates with more memory consumption. * + * @param analyzed_records A pointer to a set used to track which + * records have been analyzed to date, used to prevent infinite + * recursion. The set should be empty (but not nil) on the first call. + * * @return The total footprint. */ - virtual unsigned int Footprint() const { return 1; } + virtual unsigned int Footprint(std::set* analyzed_records) const { return 1; } // Bytes in total value object. [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See " @@ -676,7 +680,7 @@ public: void Describe(ODesc* d) const override; - unsigned int Footprint() const override; + unsigned int Footprint(std::set* analyzed_records) const override; [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See " "GHI-572.")]] unsigned int @@ -953,7 +957,7 @@ public: // the function in the frame allowing it to capture its closure. void InitDefaultFunc(detail::Frame* f); - unsigned int Footprint() const override; + unsigned int Footprint(std::set* analyzed_records) const override; [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See " "GHI-572.")]] unsigned int @@ -1381,7 +1385,7 @@ public: } RecordValPtr CoerceTo(RecordTypePtr other, bool allow_orphaning = false); - unsigned int Footprint() const override; + unsigned int Footprint(std::set* analyzed_records) const override; [[deprecated("Remove in v5.1. MemoryAllocation() is deprecated and will be removed. See " "GHI-572.")]] unsigned int @@ -1640,7 +1644,7 @@ public: const auto& RawYieldType() const { return yield_type; } const auto& RawYieldTypes() const { return yield_types; } - unsigned int Footprint() const override; + unsigned int Footprint(std::set* analyzed_records) const override; protected: /** diff --git a/src/zeek.bif b/src/zeek.bif index 07bfdf6e94..1af134f4b5 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -2008,7 +2008,8 @@ function global_container_footprints%(%): var_sizes continue; auto id_name = zeek::make_intrusive(id->Name()); - auto fp = zeek::val_mgr->Count(v->Footprint()); + std::set analyzed_records; + auto fp = zeek::val_mgr->Count(v->Footprint(&analyzed_records)); sizes->Assign(std::move(id_name), std::move(fp)); } @@ -2024,7 +2025,8 @@ function global_container_footprints%(%): var_sizes ## .. zeek:see:: global_container_footprints function val_footprint%(v: any%): count %{ - return zeek::val_mgr->Count(v->Footprint()); + std::set analyzed_records; + return zeek::val_mgr->Count(v->Footprint(&analyzed_records)); %} ## Generates a table with information about all global identifiers. The table