asn1c
asn1c copied to clipboard
ETSI ITS IVI Extension flag problem
Note: Possibly related to #290
I am unable to decode an ETSI ITS IVI message (full ASN.1 spec here) which fails at decoding the Zid which contains an extension flag:
Zid::= INTEGER (1..32,...)
GlcPart::= SEQUENCE {
zoneId Zid,
laneNumber LanePosition OPTIONAL,
zoneExtension INTEGER (0..255) OPTIONAL,
zoneHeading HeadingValue OPTIONAL,
zone Zone OPTIONAL,
...
}
The asn1c generated constraint check does not contain the extensible flag:
asn_per_constraints_t asn_PER_type_Zid_constr_1 CC_NOTUSED = {
{ APC_CONSTRAINED, 5, 5, 1, 32 } /* (1..32) */,
{ APC_UNCONSTRAINED, -1, -1, 0, 0 },
0, 0 /* No PER value map */
};
Furthermore, the decoder output does not tell me why the decoding has failed:
SET OF GlcPart decoding (constr_SET_OF.c:967)
Decoding GlcPart as SEQUENCE (UPER) (constr_SEQUENCE.c:1098)
[PER got 1<=332 bits => span 1189 +4[5..336]:5a (331) => 0x1] (asn_bit_data.c:139)
[PER got 4<=331 bits => span 1193 +4[9..336]:5a (327) => 0x4] (asn_bit_data.c:139)
Read in presence bitmap for GlcPart of 4 bits (40..) (constr_SEQUENCE.c:1121)
Decoding member "zoneId" in GlcPart (constr_SEQUENCE.c:1170)
Decoding NativeInteger Zid (UPER) (NativeInteger.c:268)
[PER got 1<=327 bits => span 1194 +5[2..328]:45 (326) => 0x1] (asn_bit_data.c:139)
Decoding unconstrained integer Zid (INTEGER.c:661)
[PER got 8<=326 bits => span 1202 +5[10..328]:45 (318) => 0x14] (asn_bit_data.c:139)
[PER got 24<=318 bits => span 1226 +6[26..320]:22 (294) => 0x8a8040] (asn_bit_data.c:139)
[PER got 24<=294 bits => span 1250 +9[26..296]:00 (270) => 0x1b5] (asn_bit_data.c:139)
[PER got 24<=270 bits => span 1274 +12[26..272]:60 (246) => 0x800014] (asn_bit_data.c:139)
[PER got 24<=246 bits => span 1298 +15[26..248]:22 (222) => 0x8a4540] (asn_bit_data.c:139)
[PER got 24<=222 bits => span 1322 +2[26..224]:08 (198) => 0x200000] (asn_bit_data.c:139)
[PER got 24<=198 bits => span 1346 +5[26..200]:36 (174) => 0xdac000] (asn_bit_data.c:139)
[PER got 16<=174 bits => span 1362 +8[18..176]:00 (158) => 0xf8] (asn_bit_data.c:139)
Freeing INTEGER as a primitive type (asn_codecs_prim.c:125)
Failed decode zoneId in GlcPart (constr_SEQUENCE.c:1180)
I suspect the problem is that Zid is being decoded as an unconstrained integer despite clearly being constrained (1..32). However, I am not sure if that is the cause of the decoding failure from the above log. Any clues to debug the issue will be much appreciated.
Update: I cross-checked the generated C code again and the constraint checking code seems to be correct:
asn_per_constraints_t asn_PER_type_Zid_constr_1 CC_NOTUSED = {
{ APC_CONSTRAINED | APC_EXTENSIBLE, 5, 5, 1, 32 } /* (1..32,...) */,
{ APC_UNCONSTRAINED, -1, -1, 0, 0 },
0, 0 /* No PER value map */
};
So, its not likely related to the extensions, but I am not sure..
I've narrowed down the source of the error: its the INTEGER_decode_uper function in INTEGER.c:
This part of code in the above function sets ct to 0 which causes the failure in decoding:
if(ct && ct->flags & APC_EXTENSIBLE) {
int inext = per_get_few_bits(pd, 1);
if(inext < 0) ASN__DECODE_STARVED;
**if(inext) ct = 0;**
}
I dont understand the logic: with inext, we're presumably extracting the extension marker bit from the per data frame. If inext is not 0 (i.e. there is an extension marker), why do we set the constraints (ct) to 0?
Modifying if(inext) ct = 0;
to if(inext < 0) ct = 0;
does solve the issue of decoding Zid but results in overflow extensions further in the message.
The full function is below:
asn_dec_rval_t
INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
const asn_TYPE_descriptor_t *td,
const asn_per_constraints_t *constraints, void **sptr,
asn_per_data_t *pd) {
const asn_INTEGER_specifics_t *specs =
(const asn_INTEGER_specifics_t *)td->specifics;
asn_dec_rval_t rval = { RC_OK, 0 };
INTEGER_t *st = (INTEGER_t *)*sptr;
const asn_per_constraint_t *ct;
int repeat;
(void)opt_codec_ctx;
if(!st) {
st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
if(!st) ASN__DECODE_FAILED;
}
if(!constraints) constraints = td->encoding_constraints.per_constraints;
ct = constraints ? &constraints->value : 0;
if(ct && ct->flags & APC_EXTENSIBLE) {
int inext = per_get_few_bits(pd, 1);
if(inext < 0) ASN__DECODE_STARVED;
if(inext) ct = 0;
}
FREEMEM(st->buf);
st->buf = 0;
st->size = 0;
if(ct) {
if(ct->flags & APC_SEMI_CONSTRAINED) {
st->buf = (uint8_t *)CALLOC(1, 2);
if(!st->buf) ASN__DECODE_FAILED;
st->size = 1;
} else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {
size_t size = (ct->range_bits + 7) >> 3;
st->buf = (uint8_t *)MALLOC(1 + size + 1);
if(!st->buf) ASN__DECODE_FAILED;
st->size = size;
}
}
/* X.691-2008/11, #13.2.2, constrained whole number */
if(ct && ct->flags != APC_UNCONSTRAINED) {
/* #11.5.6 */
ASN_DEBUG("Integer with range %d bits", ct->range_bits);
if(ct->range_bits >= 0) {
if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
ASN__DECODE_FAILED;
if(specs && specs->field_unsigned) {
unsigned long uvalue = 0;
if(uper_get_constrained_whole_number(pd,
&uvalue, ct->range_bits))
ASN__DECODE_STARVED;
ASN_DEBUG("Got value %lu + low %ld",
uvalue, ct->lower_bound);
uvalue += ct->lower_bound;
if(asn_ulong2INTEGER(st, uvalue))
ASN__DECODE_FAILED;
} else {
unsigned long uvalue = 0;
long svalue;
if(uper_get_constrained_whole_number(pd,
&uvalue, ct->range_bits))
ASN__DECODE_STARVED;
ASN_DEBUG("Got value %lu + low %ld",
uvalue, ct->lower_bound);
if(per_long_range_unrebase(uvalue, ct->lower_bound,
ct->upper_bound, &svalue)
|| asn_long2INTEGER(st, svalue)) {
ASN__DECODE_FAILED;
}
}
return rval;
}
} else {
ASN_DEBUG("Decoding unconstrained integer %s", td->name);
}
/* X.691, #12.2.3, #12.2.4 */
do {
ssize_t len = 0;
void *p = NULL;
int ret = 0;
/* Get the PER length */
len = uper_get_length(pd, -1, 0, &repeat);
if(len < 0) ASN__DECODE_STARVED;
p = REALLOC(st->buf, st->size + len + 1);
if(!p) ASN__DECODE_FAILED;
st->buf = (uint8_t *)p;
ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);
if(ret < 0) ASN__DECODE_STARVED;
st->size += len;
} while(repeat);
st->buf[st->size] = 0; /* JIC */
/* #12.2.3 */
if(ct && ct->lower_bound) {
/*
* TODO: replace by in-place arithmetics.
*/
long value = 0;
if(asn_INTEGER2long(st, &value))
ASN__DECODE_FAILED;
if(asn_imax2INTEGER(st, value + ct->lower_bound))
ASN__DECODE_FAILED;
}
return rval;
}
Getting closer...