Fix |...| operator for inner ports/enums

The `|...|` (sizeof) operator applies to ports/enums. That has returned
a count, but it causes an internal error when used as an inner value in
a record. This fixes that internal error for ports by just making the
sizeof operator return a count.

Enums could technically be negative before this change, but that is
rejected at parse time. It seems reasonable to modify the enum value
to only be non-negative, which makes the sizeof operator easier since it
can just return a count. Changing that to return an int would
potentially break scripts that use the sizeof operator and assign it to
a count.

This could technically break code that internally sets the enum value to
a negative value, but I don't think that's a very likely use.
This commit is contained in:
Evan Typanski 2024-09-11 17:46:42 +02:00
parent ba91de59b0
commit a26d2dd56c
9 changed files with 37 additions and 10 deletions

4
NEWS
View file

@ -25,6 +25,10 @@ Breaking Changes
are not affected by this change, so we keep backwards compatibility with are not affected by this change, so we keep backwards compatibility with
existing log writers. existing log writers.
* Enum values can no longer be negative even if created internally. This is
enforced at parse time for scripts, but not internally. With this change, the
``|...|`` operator for enums will properly return a count in all instances.
New Functionality New Functionality
----------------- -----------------

View file

@ -1542,6 +1542,12 @@ void EnumType::CheckAndAddName(const string& module_name, const char* name, zeek
return; return;
} }
if ( val < 0 ) {
reporter->Error("enumerator value cannot be negative");
SetError();
return;
}
auto fullname = detail::make_full_var_name(module_name.c_str(), name); auto fullname = detail::make_full_var_name(module_name.c_str(), name);
auto id = id::find(fullname); auto id = id::find(fullname);

View file

@ -594,7 +594,7 @@ void IntervalVal::ValDescribe(ODesc* d) const {
} }
} }
ValPtr PortVal::SizeVal() const { return val_mgr->Int(uint_val); } ValPtr PortVal::SizeVal() const { return val_mgr->Count(uint_val); }
uint32_t PortVal::Mask(uint32_t port_num, TransportProto port_type) { uint32_t PortVal::Mask(uint32_t port_num, TransportProto port_type) {
// Note, for ICMP one-way connections: // Note, for ICMP one-way connections:
@ -3133,10 +3133,10 @@ unsigned int RecordVal::ComputeFootprint(std::unordered_set<const Val*>* analyze
return fp; return fp;
} }
ValPtr EnumVal::SizeVal() const { return val_mgr->Int(AsInt()); } ValPtr EnumVal::SizeVal() const { return val_mgr->Count(AsCount()); }
void EnumVal::ValDescribe(ODesc* d) const { void EnumVal::ValDescribe(ODesc* d) const {
const char* ename = type->AsEnumType()->Lookup(int_val); const char* ename = type->AsEnumType()->Lookup(uint_val);
if ( ! ename ) if ( ! ename )
ename = "<undefined>"; ename = "<undefined>";

View file

@ -4,7 +4,6 @@
#include <sys/types.h> // for u_char #include <sys/types.h> // for u_char
#include <array> #include <array>
#include <list>
#include <unordered_map> #include <unordered_map>
#include <variant> #include <variant>
#include <vector> #include <vector>
@ -1497,7 +1496,7 @@ private:
const std::vector<bool>& is_managed; const std::vector<bool>& is_managed;
}; };
class EnumVal final : public detail::IntValImplementation { class EnumVal final : public detail::UnsignedValImplementation {
public: public:
ValPtr SizeVal() const override; ValPtr SizeVal() const override;
@ -1505,12 +1504,12 @@ protected:
friend class Val; friend class Val;
friend class EnumType; friend class EnumType;
friend EnumValPtr make_enum__CPP(TypePtr t, zeek_int_t i); friend EnumValPtr make_enum__CPP(TypePtr t, zeek_uint_t i);
template<class T, class... Ts> template<class T, class... Ts>
friend IntrusivePtr<T> make_intrusive(Ts&&... args); friend IntrusivePtr<T> make_intrusive(Ts&&... args);
EnumVal(EnumTypePtr t, zeek_int_t i) : detail::IntValImplementation(std::move(t), i) {} EnumVal(EnumTypePtr t, zeek_uint_t i) : detail::UnsignedValImplementation(std::move(t), i) {}
void ValDescribe(ODesc* d) const override; void ValDescribe(ODesc* d) const override;
ValPtr DoClone(CloneState* state) override; ValPtr DoClone(CloneState* state) override;

View file

@ -223,7 +223,7 @@ EnumTypePtr get_enum_type__CPP(const string& enum_type_name) {
return make_intrusive<EnumType>(enum_type_name); return make_intrusive<EnumType>(enum_type_name);
} }
EnumValPtr make_enum__CPP(TypePtr t, zeek_int_t i) { EnumValPtr make_enum__CPP(TypePtr t, zeek_uint_t i) {
auto et = cast_intrusive<EnumType>(std::move(t)); auto et = cast_intrusive<EnumType>(std::move(t));
return make_intrusive<EnumVal>(et, i); return make_intrusive<EnumVal>(et, i);
} }

View file

@ -95,7 +95,7 @@ extern EnumTypePtr get_enum_type__CPP(const std::string& enum_type_name);
// Returns an enum value corresponding to the given low-level value 'i' // Returns an enum value corresponding to the given low-level value 'i'
// in the context of the given enum type 't'. // in the context of the given enum type 't'.
extern EnumValPtr make_enum__CPP(TypePtr t, zeek_int_t i); extern EnumValPtr make_enum__CPP(TypePtr t, zeek_uint_t i);
} // namespace detail } // namespace detail
} // namespace zeek } // namespace zeek

View file

@ -1,2 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
expression warning in <...>/sizeof.zeek, line 73: count underflow (5 - 9) expression warning in <...>/sizeof.zeek, line 83: count underflow (5 - 9)

View file

@ -7,11 +7,13 @@ Expr: 18446744073709551612
Signed Expr: 4 Signed Expr: 4
Double -1.23: 1.230000 Double -1.23: 1.230000
Enum ENUM3: 2 Enum ENUM3: 2
Enum in record: 2
File 21.000000 File 21.000000
Function add_interface: 2 Function add_interface: 2
Integer -10: 10 Integer -10: 10
Interval -5.0 secs: 5.000000 Interval -5.0 secs: 5.000000
Port 80/tcp: 65616 Port 80/tcp: 65616
Port in record: 65616
Record [i=10, j=<uninitialized>, k=<uninitialized>]: 3 Record [i=10, j=<uninitialized>, k=<uninitialized>]: 3
Set: 3 Set: 3
String 'Hello': 5 String 'Hello': 5

View file

@ -20,6 +20,14 @@ type example_record: record {
k: int &optional; k: int &optional;
}; };
type example_record_with_enum: record {
e: count &default = |ENUM3|;
} &redef;
type example_record_with_port: record {
p: count &default = |80/tcp|;
} &redef;
global a: addr = 1.2.3.4; global a: addr = 1.2.3.4;
global a6: addr = [::1]; global a6: addr = [::1];
global b: bool = T; global b: bool = T;
@ -36,6 +44,8 @@ global sn: subnet = 192.168.0.0/24;
global t: table[string] of string; global t: table[string] of string;
global ti: time = current_time(); global ti: time = current_time();
global v: vector of string; global v: vector of string;
global with_enum: example_record_with_enum;
global with_port: example_record_with_port;
# Additional initialization # Additional initialization
# #
@ -80,6 +90,9 @@ print fmt("Double %s: %f", d, |d|);
# Size of enum: returns numeric value of enum constant. # Size of enum: returns numeric value of enum constant.
print fmt("Enum %s: %d", ENUM3, |ENUM3|); print fmt("Enum %s: %d", ENUM3, |ENUM3|);
# Within a record, enum sizeof should still be ok
print fmt("Enum in record: %d", |with_enum$e|);
# Size of file: returns current file size. # Size of file: returns current file size.
# Note that this is a double so that file sizes >> 4GB # Note that this is a double so that file sizes >> 4GB
# can be expressed. # can be expressed.
@ -97,6 +110,9 @@ print fmt("Interval %s: %f", iv, |iv|);
# Size of port: returns port number as a count. # Size of port: returns port number as a count.
print fmt("Port %s: %d", p, |p|); print fmt("Port %s: %d", p, |p|);
# Within a record, port sizeof should still be ok
print fmt("Port in record: %d", |with_port$p|);
# Size of record: returns number of fields (assigned + unassigned) # Size of record: returns number of fields (assigned + unassigned)
print fmt("Record %s: %d", r, |r|); print fmt("Record %s: %d", r, |r|);