From 8df4df0b8b7c8760d830c0f99e26e8f4db66967a Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 30 Jul 2013 15:19:48 -0500 Subject: [PATCH] Add a distinct tag class for file analyzers. This should prevent assignment mismatches between file and protocol analyzer tags. --- src/CMakeLists.txt | 1 + src/Tag.cc | 82 ++++++++++++++++++ src/Tag.h | 138 +++++++++++++++++++++++++++++++ src/analyzer/Component.cc | 2 +- src/analyzer/Manager.cc | 2 +- src/analyzer/Tag.cc | 84 ++----------------- src/analyzer/Tag.h | 93 ++++++--------------- src/file_analysis/CMakeLists.txt | 1 + src/file_analysis/Component.cc | 8 +- src/file_analysis/Component.h | 16 ++-- src/file_analysis/Manager.h | 2 +- src/file_analysis/Tag.cc | 24 ++++++ src/file_analysis/Tag.h | 115 ++++++++++++++++++++++++++ 13 files changed, 407 insertions(+), 161 deletions(-) create mode 100644 src/Tag.cc create mode 100644 src/Tag.h create mode 100644 src/file_analysis/Tag.cc create mode 100644 src/file_analysis/Tag.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e353dd4695..082f34fba1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -315,6 +315,7 @@ set(bro_SRCS StateAccess.cc Stats.cc Stmt.cc + Tag.cc Timer.cc Traverse.cc Trigger.cc diff --git a/src/Tag.cc b/src/Tag.cc new file mode 100644 index 0000000000..178edaa71e --- /dev/null +++ b/src/Tag.cc @@ -0,0 +1,82 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "Tag.h" +#include "Val.h" + +Tag::Tag(EnumType* etype, type_t arg_type, subtype_t arg_subtype) + { + assert(arg_type > 0); + + type = arg_type; + subtype = arg_subtype; + int64_t i = (int64)(type) | ((int64)subtype << 31); + Ref(etype); + val = new EnumVal(i, etype); + } + +Tag::Tag(EnumVal* arg_val) + { + assert(arg_val); + + val = arg_val; + Ref(val); + + int64 i = val->InternalInt(); + type = i & 0xffffffff; + subtype = (i >> 31) & 0xffffffff; + } + +Tag::Tag(const Tag& other) + { + type = other.type; + subtype = other.subtype; + val = other.val; + + if ( val ) + Ref(val); + } + +Tag::Tag() + { + type = 0; + subtype = 0; + val = 0; + } + +Tag::~Tag() + { + Unref(val); + val = 0; + } + +Tag& Tag::operator=(const Tag& other) + { + if ( this != &other ) + { + type = other.type; + subtype = other.subtype; + val = other.val; + + if ( val ) + Ref(val); + } + + return *this; + } + +EnumVal* Tag::AsEnumVal(EnumType* etype) const + { + if ( ! val ) + { + assert(type == 0 && subtype == 0); + Ref(etype); + val = new EnumVal(0, etype); + } + + return val; + } + +std::string Tag::AsString() const + { + return fmt("%" PRIu32 "/%" PRIu32, type, subtype); + } diff --git a/src/Tag.h b/src/Tag.h new file mode 100644 index 0000000000..a0c218019e --- /dev/null +++ b/src/Tag.h @@ -0,0 +1,138 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#ifndef TAG_H +#define TAG_H + +#include "config.h" +#include "util.h" +#include "Type.h" + +class EnumVal; + +/** + * Class to identify an analyzer type. + * + * Each analyzer type gets a tag consisting of a main type and subtype. The + * former is an identifier that's unique all analyzer classes. The latter is + * passed through to the analyzer instances for their use, yet not further + * interpreted by the analyzer infrastructure; it allows an analyzer to + * branch out into a set of sub-analyzers internally. Jointly, main type and + * subtype form an analyzer "tag". Each unique tag corresponds to a single + * "analyzer" from the user's perspective. At the script layer, these tags + * are mapped into enums of type \c Analyzer::Tag or Files::Tag. Internally, + * the analyzer::Manager and file_analysis::Manager maintain the mapping of tag + * to analyzer (and it also assigns them their main types), and + * analyzer::Component and file_analysis::Component create new tag. + * + * The Tag class supports all operations necessary to act as an index in a + * \c std::map. + */ +class Tag { +public: + /** + * Type for the analyzer's main type. + */ + typedef uint32 type_t; + + /** + * Type for the analyzer's subtype. + */ + typedef uint32 subtype_t; + + /** + * Returns the tag's main type. + */ + type_t Type() const { return type; } + + /** + * Returns the tag's subtype. + */ + subtype_t Subtype() const { return subtype; } + + /** + * Returns the numerical values for main and subtype inside a string + * suitable for printing. This is primarily for debugging. + */ + std::string AsString() const; + +protected: + /* + * Copy constructor. + */ + Tag(const Tag& other); + + /** + * Default constructor. This initializes the tag with an error value + * that will make \c operator \c bool return false. + */ + Tag(); + + /** + * Destructor. + */ + ~Tag(); + + /** + * Assignment operator. + */ + Tag& operator=(const Tag& other); + + /** + * Compares two tags for equality. + */ + bool operator==(const Tag& other) const + { + return type == other.type && subtype == other.subtype; + } + + /** + * Compares two tags for inequality. + */ + bool operator!=(const Tag& other) const + { + return type != other.type || subtype != other.subtype; + } + + /** + * Compares two tags for less-than relationship. + */ + bool operator<(const Tag& other) const + { + return type != other.type ? type < other.type : (subtype < other.subtype); + } + + /** + * Returns the script-layer enum that corresponds to this tag. + * The returned value does not have its ref-count increased. + * + * @param etype the script-layer enum type associated with the tag. + */ + EnumVal* AsEnumVal(EnumType* etype) const; + + /** + * Constructor. + * + * @param etype the script-layer enum type associated with the tag. + * + * @param type The main type. Note that the manager class manages the + * the value space internally, so noone else should assign main types. + * + * @param subtype The sub type, which is left to an analyzer for + * interpretation. By default it's set to zero. + */ + Tag(EnumType* etype, type_t type, subtype_t subtype = 0); + + /** + * Constructor. + * + * @param val An enum value of script type \c Analyzer::Tag. + */ + Tag(EnumVal* val); + +private: + type_t type; // Main type. + subtype_t subtype; // Subtype. + mutable EnumVal* val; // Script-layer value. +}; + +#endif diff --git a/src/analyzer/Component.cc b/src/analyzer/Component.cc index cbb0f40c20..ded0a1a2d5 100644 --- a/src/analyzer/Component.cc +++ b/src/analyzer/Component.cc @@ -8,7 +8,7 @@ using namespace analyzer; -Tag::type_t Component::type_counter = 0; +analyzer::Tag::type_t Component::type_counter = 0; Component::Component(const char* arg_name, factory_callback arg_factory, Tag::subtype_t arg_subtype, bool arg_enabled, bool arg_partial) : plugin::Component(plugin::component::ANALYZER) diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 5695dec625..3f97cbb0c8 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -341,7 +341,7 @@ const char* Manager::GetAnalyzerName(Val* val) return GetAnalyzerName(Tag(val->AsEnumVal())); } -Tag Manager::GetAnalyzerTag(const char* name) +analyzer::Tag Manager::GetAnalyzerTag(const char* name) { Component* c = Lookup(name); return c ? c->Tag() : Tag(); diff --git a/src/analyzer/Tag.cc b/src/analyzer/Tag.cc index 2f04ff17da..3ab41daf78 100644 --- a/src/analyzer/Tag.cc +++ b/src/analyzer/Tag.cc @@ -3,90 +3,20 @@ #include "Tag.h" #include "Manager.h" -#include "../NetVar.h" +analyzer::Tag analyzer::Tag::Error; -using namespace analyzer; - -Tag Tag::Error; - -Tag::Tag(type_t arg_type, subtype_t arg_subtype) +analyzer::Tag::Tag(type_t type, subtype_t subtype) + : ::Tag(analyzer_mgr->GetTagEnumType(), type, subtype) { - assert(arg_type > 0); - - type = arg_type; - subtype = arg_subtype; - int64_t i = (int64)(type) | ((int64)subtype << 31); - - EnumType* etype = analyzer_mgr->GetTagEnumType(); - Ref(etype); - val = new EnumVal(i, etype); } -Tag::Tag(EnumVal* arg_val) +analyzer::Tag& analyzer::Tag::operator=(const analyzer::Tag& other) { - assert(arg_val); - - val = arg_val; - Ref(val); - - int64 i = val->InternalInt(); - type = i & 0xffffffff; - subtype = (i >> 31) & 0xffffffff; - } - -Tag::Tag(const Tag& other) - { - type = other.type; - subtype = other.subtype; - val = other.val; - - if ( val ) - Ref(val); - } - -Tag::Tag() - { - type = 0; - subtype = 0; - val = 0; - } - -Tag::~Tag() - { - Unref(val); - val = 0; - } - -Tag& Tag::operator=(const Tag& other) - { - if ( this != &other ) - { - type = other.type; - subtype = other.subtype; - val = other.val; - - if ( val ) - Ref(val); - } - + ::Tag::operator=(other); return *this; } -EnumVal* Tag::AsEnumVal() const +EnumVal* analyzer::Tag::AsEnumVal() const { - if ( ! val ) - { - assert(analyzer_mgr); - assert(type == 0 && subtype == 0); - EnumType* etype = analyzer_mgr->GetTagEnumType(); - Ref(etype); - val = new EnumVal(0, etype); - } - - return val; - } - -std::string Tag::AsString() const - { - return fmt("%" PRIu32 "/%" PRIu32, type, subtype); + return ::Tag::AsEnumVal(analyzer_mgr->GetTagEnumType()); } diff --git a/src/analyzer/Tag.h b/src/analyzer/Tag.h index edb0ade8a7..8ac151e4b5 100644 --- a/src/analyzer/Tag.h +++ b/src/analyzer/Tag.h @@ -5,90 +5,44 @@ #include "config.h" #include "util.h" +#include "../Tag.h" class EnumVal; -namespace file_analysis { -class Manager; -class Component; -} - namespace analyzer { class Manager; class Component; /** - * Class to identify an analyzer type. + * Class to identify a protocol analyzer type. * - * Each analyzer type gets a tag consisting of a main type and subtype. The - * former is an identifier that's unique all analyzer classes. The latter is - * passed through to the analyzer instances for their use, yet not further - * interpreted by the analyzer infrastructure; it allows an analyzer to - * branch out into a set of sub-analyzers internally. Jointly, main type and - * subtype form an analyzer "tag". Each unique tag corresponds to a single - * "analyzer" from the user's perspective. At the script layer, these tags - * are mapped into enums of type \c Analyzer::Tag. Internally, the - * analyzer::Manager maintains the mapping of tag to analyzer (and it also - * assigns them their main types), and analyzer::Component creates new - * tags. - * - * The Tag class supports all operations necessary to act as an index in a - * \c std::map. + * The script-layer analogue is Analyzer::Tag. */ -class Tag { +class Tag : public ::Tag { public: - /** - * Type for the analyzer's main type. - */ - typedef uint32 type_t; - - /** - * Type for the analyzer's subtype. - */ - typedef uint32 subtype_t; - /* * Copy constructor. */ - Tag(const Tag& other); + Tag(const Tag& other) : ::Tag(other) {} /** * Default constructor. This initializes the tag with an error value * that will make \c operator \c bool return false. */ - Tag(); + Tag() : ::Tag() {} /** * Destructor. */ - ~Tag(); - - /** - * Returns the tag's main type. - */ - type_t Type() const { return type; } - - /** - * Returns the tag's subtype. - */ - subtype_t Subtype() const { return subtype; } - - /** - * Returns the \c Analyzer::Tag enum that corresponds to this tag. - * The returned value is \a does not have its ref-count increased. - */ - EnumVal* AsEnumVal() const; - - /** - * Returns the numerical values for main and subtype inside a string - * suitable for printing. This is primarily for debugging. - */ - std::string AsString() const; + ~Tag() {} /** * Returns false if the tag represents an error value rather than a * legal analyzer type. + * TODO: make this conversion operator "explicit" (C++11) or use a + * "safe bool" idiom (not necessary if "explicit" is available), + * otherwise this may allow nonsense/undesired comparison operations. */ operator bool() const { return *this != Tag(); } @@ -102,7 +56,7 @@ public: */ bool operator==(const Tag& other) const { - return type == other.type && subtype == other.subtype; + return ::Tag::operator==(other); } /** @@ -110,7 +64,7 @@ public: */ bool operator!=(const Tag& other) const { - return type != other.type || subtype != other.subtype; + return ::Tag::operator!=(other); } /** @@ -118,23 +72,29 @@ public: */ bool operator<(const Tag& other) const { - return type != other.type ? type < other.type : (subtype < other.subtype); + return ::Tag::operator<(other); } + /** + * Returns the \c Analyzer::Tag enum that corresponds to this tag. + * The returned value does not have its ref-count increased. + * + * @param etype the script-layer enum type associated with the tag. + */ + EnumVal* AsEnumVal() const; + static Tag Error; protected: friend class analyzer::Manager; friend class analyzer::Component; - friend class file_analysis::Manager; - friend class file_analysis::Component; /** * Constructor. * * @param type The main type. Note that the \a analyzer::Manager * manages the value space internally, so noone else should assign - * any main tyoes. + * any main types. * * @param subtype The sub type, which is left to an analyzer for * interpretation. By default it's set to zero. @@ -144,14 +104,9 @@ protected: /** * Constructor. * - * @param val An enuam value of script type \c Analyzer::Tag. + * @param val An enum value of script type \c Analyzer::Tag. */ - Tag(EnumVal* val); - -private: - type_t type; // Main type. - subtype_t subtype; // Subtype. - mutable EnumVal* val; // Analyzer::Tag value. + Tag(EnumVal* val) : ::Tag(val) {} }; } diff --git a/src/file_analysis/CMakeLists.txt b/src/file_analysis/CMakeLists.txt index f22c293cc4..709790cfaf 100644 --- a/src/file_analysis/CMakeLists.txt +++ b/src/file_analysis/CMakeLists.txt @@ -14,6 +14,7 @@ set(file_analysis_SRCS Analyzer.h AnalyzerSet.cc Component.cc + Tag.cc ) bif_target(file_analysis.bif) diff --git a/src/file_analysis/Component.cc b/src/file_analysis/Component.cc index 99531e40f5..8ddd9cceaf 100644 --- a/src/file_analysis/Component.cc +++ b/src/file_analysis/Component.cc @@ -8,17 +8,17 @@ using namespace file_analysis; -analyzer::Tag::type_t Component::type_counter = 0; +file_analysis::Tag::type_t Component::type_counter = 0; Component::Component(const char* arg_name, factory_callback arg_factory, - analyzer::Tag::subtype_t arg_subtype) + file_analysis::Tag::subtype_t arg_subtype) : plugin::Component(plugin::component::FILE_ANALYZER) { name = copy_string(arg_name); canon_name = canonify_name(arg_name); factory = arg_factory; - tag = analyzer::Tag(++type_counter, arg_subtype); + tag = file_analysis::Tag(++type_counter, arg_subtype); } Component::Component(const Component& other) @@ -36,7 +36,7 @@ Component::~Component() delete [] canon_name; } -analyzer::Tag Component::Tag() const +file_analysis::Tag Component::Tag() const { return tag; } diff --git a/src/file_analysis/Component.h b/src/file_analysis/Component.h index 3cdc69efdf..bd690bc081 100644 --- a/src/file_analysis/Component.h +++ b/src/file_analysis/Component.h @@ -3,7 +3,7 @@ #ifndef FILE_ANALYZER_PLUGIN_COMPONENT_H #define FILE_ANALYZER_PLUGIN_COMPONENT_H -#include "analyzer/Tag.h" +#include "Tag.h" #include "plugin/Component.h" #include "Val.h" @@ -41,12 +41,12 @@ public: * * @param subtype A subtype associated with this component that * further distinguishes it. The subtype will be integrated into - * the analyzer::Tag that the manager associates with this analyzer, - * and analyzer instances can accordingly access it via analyzer::Tag(). - * If not used, leave at zero. + * the file_analysis::Tag that the manager associates with this analyzer, + * and analyzer instances can accordingly access it via + * file_analysis::Tag(). If not used, leave at zero. */ Component(const char* name, factory_callback factory, - analyzer::Tag::subtype_t subtype = 0); + file_analysis::Tag::subtype_t subtype = 0); /** * Copy constructor. @@ -84,7 +84,7 @@ public: * generated for each new Components, and hence unique across all of * them. */ - analyzer::Tag Tag() const; + file_analysis::Tag Tag() const; /** * Generates a human-readable description of the component's main @@ -98,10 +98,10 @@ private: const char* name; // The analyzer's name. const char* canon_name; // The analyzer's canonical name. factory_callback factory; // The analyzer's factory callback. - analyzer::Tag tag; // The automatically assigned analyzer tag. + file_analysis::Tag tag; // The automatically assigned analyzer tag. // Global counter used to generate unique tags. - static analyzer::Tag::type_t type_counter; + static file_analysis::Tag::type_t type_counter; }; } diff --git a/src/file_analysis/Manager.h b/src/file_analysis/Manager.h index a93e78c638..55ff0896d7 100644 --- a/src/file_analysis/Manager.h +++ b/src/file_analysis/Manager.h @@ -294,7 +294,7 @@ protected: private: typedef map analyzer_map_by_name; - typedef map analyzer_map_by_tag; + typedef map analyzer_map_by_tag; typedef map analyzer_map_by_val; void RegisterAnalyzerComponent(Component* component); diff --git a/src/file_analysis/Tag.cc b/src/file_analysis/Tag.cc new file mode 100644 index 0000000000..6f0774a4b4 --- /dev/null +++ b/src/file_analysis/Tag.cc @@ -0,0 +1,24 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "Tag.h" +#include "Manager.h" + +using namespace file_analysis; + +file_analysis::Tag file_analysis::Tag::Error; + +file_analysis::Tag::Tag(type_t type, subtype_t subtype) + : ::Tag(file_mgr->GetTagEnumType(), type, subtype) + { + } + +file_analysis::Tag& file_analysis::Tag::operator=(const file_analysis::Tag& other) + { + ::Tag::operator=(other); + return *this; + } + +EnumVal* file_analysis::Tag::AsEnumVal() const + { + return ::Tag::AsEnumVal(file_mgr->GetTagEnumType()); + } diff --git a/src/file_analysis/Tag.h b/src/file_analysis/Tag.h new file mode 100644 index 0000000000..85c20da5b5 --- /dev/null +++ b/src/file_analysis/Tag.h @@ -0,0 +1,115 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#ifndef FILE_ANALYZER_TAG_H +#define FILE_ANALYZER_TAG_H + +#include "config.h" +#include "util.h" +#include "../Tag.h" + +class EnumVal; + +namespace file_analysis { + +class Manager; +class Component; + +/** + * Class to identify a file analyzer type. + * + * The script-layer analogue is Files::Tag. + */ +class Tag : public ::Tag { +public: + /* + * Copy constructor. + */ + Tag(const Tag& other) : ::Tag(other) {} + + /** + * Default constructor. This initializes the tag with an error value + * that will make \c operator \c bool return false. + */ + Tag() : ::Tag() {} + + /** + * Destructor. + */ + ~Tag() {} + + /** + * Returns false if the tag represents an error value rather than a + * legal analyzer type. + * TODO: make this conversion operator "explicit" (C++11) or use a + * "safe bool" idiom (not necessary if "explicit" is available), + * otherwise this may allow nonsense/undesired comparison operations. + * + */ + operator bool() const { return *this != Tag(); } + + /** + * Assignment operator. + */ + Tag& operator=(const Tag& other); + + /** + * Compares two tags for equality. + */ + bool operator==(const Tag& other) const + { + return ::Tag::operator==(other); + } + + /** + * Compares two tags for inequality. + */ + bool operator!=(const Tag& other) const + { + return ::Tag::operator!=(other); + } + + /** + * Compares two tags for less-than relationship. + */ + bool operator<(const Tag& other) const + { + return ::Tag::operator<(other); + } + + /** + * Returns the \c Files::Tag enum that corresponds to this tag. + * The returned value does not have its ref-count increased. + * + * @param etype the script-layer enum type associated with the tag. + */ + EnumVal* AsEnumVal() const; + + static Tag Error; + +protected: + friend class file_analysis::Manager; + friend class file_analysis::Component; + + /** + * Constructor. + * + * @param type The main type. Note that the \a file_analysis::Manager + * manages the value space internally, so noone else should assign + * main tyoes. + * + * @param subtype The sub type, which is left to an analyzer for + * interpretation. By default it's set to zero. + */ + Tag(type_t type, subtype_t subtype = 0); + + /** + * Constructor. + * + * @param val An enum value of script type \c Files::Tag. + */ + Tag(EnumVal* val) : ::Tag(val) {} +}; + +} + +#endif