asn1c icon indicating copy to clipboard operation
asn1c copied to clipboard

ETSI ITS IVI Extension flag problem

Open sandman opened this issue 4 years ago • 2 comments

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.

sandman avatar Jun 02 '20 18:06 sandman

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

sandman avatar Jun 02 '20 18:06 sandman

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

sandman avatar Jun 02 '20 22:06 sandman