Add a distinct tag class for file analyzers.

This should prevent assignment mismatches between file and protocol
analyzer tags.
This commit is contained in:
Jon Siwek 2013-07-30 15:19:48 -05:00
parent d84f6e012c
commit 8df4df0b8b
13 changed files with 407 additions and 161 deletions

View file

@ -315,6 +315,7 @@ set(bro_SRCS
StateAccess.cc StateAccess.cc
Stats.cc Stats.cc
Stmt.cc Stmt.cc
Tag.cc
Timer.cc Timer.cc
Traverse.cc Traverse.cc
Trigger.cc Trigger.cc

82
src/Tag.cc Normal file
View file

@ -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);
}

138
src/Tag.h Normal file
View file

@ -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

View file

@ -8,7 +8,7 @@
using namespace analyzer; 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) 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) : plugin::Component(plugin::component::ANALYZER)

View file

@ -341,7 +341,7 @@ const char* Manager::GetAnalyzerName(Val* val)
return GetAnalyzerName(Tag(val->AsEnumVal())); return GetAnalyzerName(Tag(val->AsEnumVal()));
} }
Tag Manager::GetAnalyzerTag(const char* name) analyzer::Tag Manager::GetAnalyzerTag(const char* name)
{ {
Component* c = Lookup(name); Component* c = Lookup(name);
return c ? c->Tag() : Tag(); return c ? c->Tag() : Tag();

View file

@ -3,90 +3,20 @@
#include "Tag.h" #include "Tag.h"
#include "Manager.h" #include "Manager.h"
#include "../NetVar.h" analyzer::Tag analyzer::Tag::Error;
using namespace analyzer; analyzer::Tag::Tag(type_t type, subtype_t subtype)
: ::Tag(analyzer_mgr->GetTagEnumType(), type, subtype)
Tag Tag::Error;
Tag::Tag(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);
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); ::Tag::operator=(other);
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; return *this;
} }
EnumVal* Tag::AsEnumVal() const EnumVal* analyzer::Tag::AsEnumVal() const
{ {
if ( ! val ) return ::Tag::AsEnumVal(analyzer_mgr->GetTagEnumType());
{
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);
} }

View file

@ -5,90 +5,44 @@
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
#include "../Tag.h"
class EnumVal; class EnumVal;
namespace file_analysis {
class Manager;
class Component;
}
namespace analyzer { namespace analyzer {
class Manager; class Manager;
class Component; 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 * The script-layer analogue is Analyzer::Tag.
* 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.
*/ */
class Tag { class Tag : public ::Tag {
public: public:
/**
* Type for the analyzer's main type.
*/
typedef uint32 type_t;
/**
* Type for the analyzer's subtype.
*/
typedef uint32 subtype_t;
/* /*
* Copy constructor. * Copy constructor.
*/ */
Tag(const Tag& other); Tag(const Tag& other) : ::Tag(other) {}
/** /**
* Default constructor. This initializes the tag with an error value * Default constructor. This initializes the tag with an error value
* that will make \c operator \c bool return false. * that will make \c operator \c bool return false.
*/ */
Tag(); Tag() : ::Tag() {}
/** /**
* Destructor. * Destructor.
*/ */
~Tag(); ~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;
/** /**
* Returns false if the tag represents an error value rather than a * Returns false if the tag represents an error value rather than a
* legal analyzer type. * 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(); } operator bool() const { return *this != Tag(); }
@ -102,7 +56,7 @@ public:
*/ */
bool operator==(const Tag& other) const 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 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 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; static Tag Error;
protected: protected:
friend class analyzer::Manager; friend class analyzer::Manager;
friend class analyzer::Component; friend class analyzer::Component;
friend class file_analysis::Manager;
friend class file_analysis::Component;
/** /**
* Constructor. * Constructor.
* *
* @param type The main type. Note that the \a analyzer::Manager * @param type The main type. Note that the \a analyzer::Manager
* manages the value space internally, so noone else should assign * 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 * @param subtype The sub type, which is left to an analyzer for
* interpretation. By default it's set to zero. * interpretation. By default it's set to zero.
@ -144,14 +104,9 @@ protected:
/** /**
* Constructor. * 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); Tag(EnumVal* val) : ::Tag(val) {}
private:
type_t type; // Main type.
subtype_t subtype; // Subtype.
mutable EnumVal* val; // Analyzer::Tag value.
}; };
} }

View file

@ -14,6 +14,7 @@ set(file_analysis_SRCS
Analyzer.h Analyzer.h
AnalyzerSet.cc AnalyzerSet.cc
Component.cc Component.cc
Tag.cc
) )
bif_target(file_analysis.bif) bif_target(file_analysis.bif)

View file

@ -8,17 +8,17 @@
using namespace file_analysis; 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, 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) : plugin::Component(plugin::component::FILE_ANALYZER)
{ {
name = copy_string(arg_name); name = copy_string(arg_name);
canon_name = canonify_name(arg_name); canon_name = canonify_name(arg_name);
factory = arg_factory; factory = arg_factory;
tag = analyzer::Tag(++type_counter, arg_subtype); tag = file_analysis::Tag(++type_counter, arg_subtype);
} }
Component::Component(const Component& other) Component::Component(const Component& other)
@ -36,7 +36,7 @@ Component::~Component()
delete [] canon_name; delete [] canon_name;
} }
analyzer::Tag Component::Tag() const file_analysis::Tag Component::Tag() const
{ {
return tag; return tag;
} }

View file

@ -3,7 +3,7 @@
#ifndef FILE_ANALYZER_PLUGIN_COMPONENT_H #ifndef FILE_ANALYZER_PLUGIN_COMPONENT_H
#define FILE_ANALYZER_PLUGIN_COMPONENT_H #define FILE_ANALYZER_PLUGIN_COMPONENT_H
#include "analyzer/Tag.h" #include "Tag.h"
#include "plugin/Component.h" #include "plugin/Component.h"
#include "Val.h" #include "Val.h"
@ -41,12 +41,12 @@ public:
* *
* @param subtype A subtype associated with this component that * @param subtype A subtype associated with this component that
* further distinguishes it. The subtype will be integrated into * further distinguishes it. The subtype will be integrated into
* the analyzer::Tag that the manager associates with this analyzer, * the file_analysis::Tag that the manager associates with this analyzer,
* and analyzer instances can accordingly access it via analyzer::Tag(). * and analyzer instances can accordingly access it via
* If not used, leave at zero. * file_analysis::Tag(). If not used, leave at zero.
*/ */
Component(const char* name, factory_callback factory, Component(const char* name, factory_callback factory,
analyzer::Tag::subtype_t subtype = 0); file_analysis::Tag::subtype_t subtype = 0);
/** /**
* Copy constructor. * Copy constructor.
@ -84,7 +84,7 @@ public:
* generated for each new Components, and hence unique across all of * generated for each new Components, and hence unique across all of
* them. * them.
*/ */
analyzer::Tag Tag() const; file_analysis::Tag Tag() const;
/** /**
* Generates a human-readable description of the component's main * Generates a human-readable description of the component's main
@ -98,10 +98,10 @@ private:
const char* name; // The analyzer's name. const char* name; // The analyzer's name.
const char* canon_name; // The analyzer's canonical name. const char* canon_name; // The analyzer's canonical name.
factory_callback factory; // The analyzer's factory callback. 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. // Global counter used to generate unique tags.
static analyzer::Tag::type_t type_counter; static file_analysis::Tag::type_t type_counter;
}; };
} }

View file

@ -294,7 +294,7 @@ protected:
private: private:
typedef map<string, Component*> analyzer_map_by_name; typedef map<string, Component*> analyzer_map_by_name;
typedef map<analyzer::Tag, Component*> analyzer_map_by_tag; typedef map<file_analysis::Tag, Component*> analyzer_map_by_tag;
typedef map<int, Component*> analyzer_map_by_val; typedef map<int, Component*> analyzer_map_by_val;
void RegisterAnalyzerComponent(Component* component); void RegisterAnalyzerComponent(Component* component);

24
src/file_analysis/Tag.cc Normal file
View file

@ -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());
}

115
src/file_analysis/Tag.h Normal file
View file

@ -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