pyuavcan: DSDL length validation

This commit is contained in:
Pavel Kirienko
2015-04-30 11:50:01 +03:00
parent 898fe67225
commit 0ea4e5e4e0
6 changed files with 38 additions and 44 deletions
@@ -8,4 +8,4 @@ uint8 PROTOCOL_ID_RTCM2 = 2
uint8 PROTOCOL_ID_RTCM3 = 3 uint8 PROTOCOL_ID_RTCM3 = 3
uint8 protocol_id uint8 protocol_id
uint8[<=400] data uint8[<=100] data
@@ -41,7 +41,7 @@ TEST(Dsdl, Streaming)
os << get_node_info_rsp << std::endl << "==========" << std::endl; os << get_node_info_rsp << std::endl << "==========" << std::endl;
root_ns_a::Deep ps; root_ns_a::Deep ps;
ps.a.resize(2); ps.a.resize(1);
os << ps << std::endl << "==========" << std::endl; os << ps << std::endl << "==========" << std::endl;
static const std::string Reference = static const std::string Reference =
@@ -81,45 +81,19 @@ TEST(Dsdl, Streaming)
" scalar: 0\n" " scalar: 0\n"
" vector: \n" " vector: \n"
" - \n" " - \n"
" vector: [0, 0, 0, 0]\n" " vector: [0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" " bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n" " - \n"
" vector: [0, 0, 0, 0]\n" " vector: [0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n"
" vector: [0, 0, 0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n"
" scalar: 0\n"
" vector: \n"
" - \n"
" vector: [0, 0, 0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n"
" vector: [0, 0, 0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n"
" vector: [0, 0, 0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" " bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
"b: \n" "b: \n"
" - \n" " - \n"
" vector: [0, 0, 0, 0]\n" " vector: [0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" " bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n" " - \n"
" vector: [0, 0, 0, 0]\n" " vector: [0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
" - \n"
" vector: [0, 0, 0, 0]\n"
" bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" " bools: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n"
"==========\n"; "==========\n";
std::cout << os.str(); std::cout << os.str();
ASSERT_EQ(Reference, os.str()); ASSERT_EQ(Reference, os.str());
} }
TEST(Dsdl, OStream)
{
root_ns_a::Deep ps;
ps.a.resize(2);
uavcan::OStream::instance() << ps << uavcan::OStream::endl;
}
+1 -1
View File
@@ -5,4 +5,4 @@
# #
float32 scalar float32 scalar
B[3] vector B[2] vector
+1 -1
View File
@@ -1,2 +1,2 @@
float64[4] vector float64[2] vector
bool[16] bools bool[16] bools
@@ -3,6 +3,6 @@
# #
bool c bool c
uint8[<64] str uint8[<20] str
A[<3] a A[<2] a
B[3] b B[2] b
+27 -7
View File
@@ -22,8 +22,12 @@ except NameError:
long = int long = int
MAX_FULL_TYPE_NAME_LEN = 80 MAX_FULL_TYPE_NAME_LEN = 80
DATA_TYPE_ID_MAX = 2047 # TODO: different limits for messages and services
MAX_DATA_STRUCT_LEN_BYTES = 439 # TODO: different limits for messages and services SERVICE_DATA_TYPE_ID_MAX = 511
MESSAGE_DATA_TYPE_ID_MAX = 2047
MAX_SERVICE_STRUCT_LEN_BYTES = 439
MAX_MESSAGE_STRUCT_LEN_BYTES = 126 # Broadcast
class Type: class Type:
''' '''
@@ -286,7 +290,6 @@ class Parser:
default_dtid = int(default_dtid) default_dtid = int(default_dtid)
except ValueError: except ValueError:
error('Invalid default data type ID [%s]', default_dtid) error('Invalid default data type ID [%s]', default_dtid)
validate_data_type_id(default_dtid)
full_name = self._namespace_from_filename(filename) + '.' + name full_name = self._namespace_from_filename(filename) + '.' + name
validate_compound_type_full_name(full_name) validate_compound_type_full_name(full_name)
return full_name, default_dtid return full_name, default_dtid
@@ -492,6 +495,7 @@ class Parser:
max_bitlen = t.get_max_bitlen() max_bitlen = t.get_max_bitlen()
max_bytelen = bitlen_to_bytelen(max_bitlen) max_bytelen = bitlen_to_bytelen(max_bitlen)
validate_data_type_id(t)
validate_data_struct_len(t) validate_data_struct_len(t)
self.log.info('Type [%s], default DTID: %s, signature: %08x, maxbits: %s, maxbytes: %s, DSSD:', self.log.info('Type [%s], default DTID: %s, signature: %08x, maxbits: %s, maxbytes: %s, DSSD:',
full_typename, default_dtid, t.get_dsdl_signature(), max_bitlen, max_bytelen) full_typename, default_dtid, t.get_dsdl_signature(), max_bitlen, max_bytelen)
@@ -560,19 +564,35 @@ def validate_compound_type_full_name(name):
def validate_attribute_name(name): def validate_attribute_name(name):
enforce(re.match(r'[a-zA-Z][a-zA-Z0-9_]*$', name), 'Invalid attribute name [%s]', name) enforce(re.match(r'[a-zA-Z][a-zA-Z0-9_]*$', name), 'Invalid attribute name [%s]', name)
def validate_data_type_id(dtid): def validate_data_type_id(t):
enforce(0 <= dtid <= DATA_TYPE_ID_MAX, 'Invalid data type ID [%s]', dtid) if t.default_dtid is None:
return
if t.kind == t.KIND_MESSAGE:
enforce(0 <= t.default_dtid <= MESSAGE_DATA_TYPE_ID_MAX,
'Invalid data type ID for message [%s]', t.default_dtid)
elif t.kind == t.KIND_SERVICE:
enforce(0 <= t.default_dtid <= SERVICE_DATA_TYPE_ID_MAX,
'Invalid data type ID for service [%s]', t.default_dtid)
else:
error('Invalid kind: %s', t.kind)
def validate_data_struct_len(t): def validate_data_struct_len(t):
enforce(t.category == t.CATEGORY_COMPOUND, 'Data structure length can be enforced only for compound types') enforce(t.category == t.CATEGORY_COMPOUND, 'Data structure length can be enforced only for compound types')
# EXtracting sizes
if t.kind == t.KIND_MESSAGE: if t.kind == t.KIND_MESSAGE:
bitlens = [t.get_max_bitlen()] bitlens = [t.get_max_bitlen()]
elif t.kind == t.KIND_SERVICE: elif t.kind == t.KIND_SERVICE:
bitlens = t.get_max_bitlen_request(), t.get_max_bitlen_response() bitlens = t.get_max_bitlen_request(), t.get_max_bitlen_response()
# Detecting the limit
if t.kind == t.KIND_MESSAGE and t.default_dtid is not None:
max_bytes = MAX_MESSAGE_STRUCT_LEN_BYTES
else:
max_bytes = MAX_SERVICE_STRUCT_LEN_BYTES
# Checking
for bitlen in bitlens: for bitlen in bitlens:
bytelen = bitlen_to_bytelen(bitlen) bytelen = bitlen_to_bytelen(bitlen)
enforce(0 <= bytelen <= MAX_DATA_STRUCT_LEN_BYTES, enforce(0 <= bytelen <= max_bytes,
'Max data structure length is invalid: %d bits, %d bytes', bitlen, bytelen) 'Max data structure length is invalid: %d bits, %d bytes; limit %d bytes', bitlen, bytelen, max_bytes)
def parse_namespaces(source_dirs, search_dirs=None): def parse_namespaces(source_dirs, search_dirs=None):