A proof-of-concept opaque type.

This is just for playing around for the moment. It tries to address
the situation that a bif creates a C-level data structure that is then
to be manipulated with further bifs (but not with other script-level
operators). There are two problems with that:

    - We don't have a type at the script-level to represent the
    created data structure.

    - We can't just pass C-level pointers around (say, via "any")
    because then garbage collection wouldn't clean up after us.

This patch allows to wrap such a pointer with a record:

    type Foo = record {
        opaque: any;
        };

The bifs simply pass around instances of this record, while internally
storing a C pointer to the data structure instance in its only field.

Internally, "opaque" is an instance of a new Val-derived class
OpaqueVal. It gets cleaned up via ref-counting as usual and deletes
the C data structure automatically when done.
This commit is contained in:
Robin Sommer 2011-05-03 22:22:17 -07:00
parent 4aa844aa87
commit 17e17c0e6b
6 changed files with 104 additions and 0 deletions

View file

@ -274,6 +274,10 @@ type entropy_test_result: record {
serial_correlation: double; serial_correlation: double;
}; };
type test_object: record {
opaque: any;
};
# Prototypes of Bro built-in functions. # Prototypes of Bro built-in functions.
@load strings.bif.bro @load strings.bif.bro
@load bro.bif.bro @load bro.bif.bro

View file

@ -1030,6 +1030,47 @@ protected:
VectorType* vector_type; VectorType* vector_type;
}; };
// An opaque value of script type "any" that can only be manipulated via
// bifs. The value is a smart pointer that wraps a C pointer to an object of
// type T, which will be deleted when the value is no longer referenced. At
// the script level, the value is handled in a type-safe manner by embedding
// it into a record value.
template<class T>
class OpaqueVal : public Val {
public:
// Takes ownership of the object.
OpaqueVal(RecordType* arg_rt, T* arg_obj) : Val(TYPE_ANY)
{
obj = arg_obj;
rt = arg_rt;
rt->Ref();
assert(rt->NumFields() == 1);
}
~OpaqueVal()
{
delete obj;
Unref(rt);
}
T* AsObject() { return obj; }
const T* AsObject() const { return obj; }
// This returns a ref'ed RecordVal.
RecordVal* MakeRecordVal()
{
RecordVal* rv = new RecordVal(rt);
rv->Assign(0, this);
Ref();
return rv;
}
private:
T* obj;
RecordType* rt;
bool refed;
};
// Checks the given value for consistency with the given type. If an // Checks the given value for consistency with the given type. If an
// exact match, returns it. If promotable, returns the promoted version, // exact match, returns it. If promotable, returns the promoted version,

View file

@ -3327,3 +3327,33 @@ function entropy_test_finish%(index: any%): entropy_test_result
delete s; delete s;
return ent_result; return ent_result;
%} %}
%%{
class TestObject
{
public:
TestObject() { fprintf(stderr, "ctor %p\n", this); }
~TestObject() { fprintf(stderr, "dtor %p\n", this); }
};
%%}
function create_test_object%(%) : test_object
%{
TestObject* obj = new TestObject;
OpaqueVal<TestObject>* v = new OpaqueVal<TestObject>(BifType::Record::test_object, obj);
RecordVal* rv = v->MakeRecordVal();
Unref(v);
return rv;
%}
function do_something_with_test_object%(rv: test_object%) : any
%{
OpaqueVal<TestObject>* v = (OpaqueVal<TestObject>*) rv->AsRecordVal()->Lookup(0);
TestObject* obj = v->AsObject();
fprintf(stderr, "doing something with %p\n", obj);
return 0;
%}

View file

@ -51,6 +51,8 @@ enum rpc_status %{
RPC_UNKNOWN_ERROR, RPC_UNKNOWN_ERROR,
%} %}
type test_object: record;
module Log; module Log;
enum Writer %{ enum Writer %{

View file

@ -0,0 +1,9 @@
ctor 0x673ed40
doing something with 0x673ed40
ctor 0x673b290
dtor 0x673ed40
ctor 0x6785890
dtor 0x673b290
{
[1] = [opaque=<no value description>]
}

View file

@ -0,0 +1,18 @@
# @TEST-EXEC: bro %INPUT >output 2>&1
# @TEST-EXEC: btest-diff output
global obj: test_object;
global t: table[count] of test_object;
obj = create_test_object();
do_something_with_test_object(obj);
obj = create_test_object();
t[1] = obj;
print t;
delete t[1];
obj = create_test_object();