[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RE: C-Backend: Bug in choice decoding with indefinite lengths
Hanspeter,
Sorry I did not get to respond earlier, but while your example is odd,
it is still valid ASN.1 and the ASN.1 compiler should generate the
correct code. I figure you had more a more complex ASN.1 syntax that
you paired down just for the sake of explaining the problem. In certain
circumstances where you have more than one choice and one is marked
optional and both contain choices of the same types it may make sense to
tag the choice itself to avoid ambiguity rather than to tag each member
within the choice. This approach could result in less explicit tags if
it means that you only have to tag one item compared to tagging each
item in the choice. I understand it is all style so you could go either
way, but we certainly need to fix the compiler if it is generating bad
code. We will incorporate a fix for this into the next patch or
release.
--Tom
-----Original Message-----
From: owner-imc-snacc@xxxxxxxxxxxx [mailto:owner-imc-snacc@xxxxxxxxxxxx]
On Behalf Of Hanspeter Halle
Sent: Friday, March 03, 2006 5:11 AM
To: imc-snacc@xxxxxxx
Subject: C-Backend: Bug in choice decoding with indefinite lengths
Hi all,
I've got decoding errors in PDU's I've received, which had a mixture of
definite and indefinite lengths. As the complete asn1 definition is a
bit
complex I tried to reproduce the problem with an easier one:
TSeq ::= SEQUENCE
{
ch [1] CHOICE
{
c1 [0] OCTET STRING,
c2 [1] INTEGER
}
}
The generated code for the sequence looks like this:
...
tagId1 = BDecTag (b, &totalElmtsLen1, env);
if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 1))))
{
elmtLen1 = BDecLen (b, &totalElmtsLen1, env);
(v->ch) = (TSeqChoice*)Asn1Alloc(sizeof(TSeqChoice));
tagId2 = BDecTag (b, &totalElmtsLen1, env);
elmtLen2 = BDecLen (b, &totalElmtsLen1, env);
BDecTSeqChoiceContent (b, tagId2, elmtLen2, (v->ch),
&totalElmtsLen1,
env);
if (elmtLen1 == INDEFINITE_LEN)
BDecEoc(b, &totalElmtsLen1, env);
if (elmtLen1 == INDEFINITE_LEN)
BDecEoc (b, &totalElmtsLen1, env);
seqDone = TRUE;
if (elmtLen0 == INDEFINITE_LEN)
BDecEoc (b, &totalElmtsLen1, env);
else if (totalElmtsLen1 != elmtLen0)
longjmp (env, -101);
}
else
longjmp (env, -102);
...
It's obvious that this won't work if indefinite lengths are used,
because it
requires 3 EOC's at the end of the PDU having only 2 levels of
structured
data. Searching for the the bad code in the C-Backend I found that the
additional EOC checking needed for tagged choices is generated 2 times,
one
time in PrintCElmtDecodeCode and one time after each call to
PrintCElmtDecodeCode.
As I guess it's better to handle it at a place, where the length
decoding is
done too, I would propose the patch below. This works fine for me, but I
don't know if it imposes problems for other asn1 files.
Hanspeter
--- gen-dec.c.org 2004-03-12 19:51:20.000000000 +0100
+++ gen-dec.c 2006-03-03 10:26:05.000000000 +0100
@@ -978,16 +978,6 @@
if ((builtinType == BASICTYPE_ANY) ||
(builtinType == BASICTYPE_ANYDEFINEDBY))
PrintEocDecoders (src, elmtLevel, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
- /*
- * must check for another EOC for tagged CHOICEs
- * since the choice decoder routines do not check
- * for an EOC on the choice's overall length -
- * they are only passed the tag/len of the choice's
- * component.
- */
- else if ((builtinType == BASICTYPE_CHOICE) &&
!(stoleChoiceTags) &&
- ((tags != NULL) && !LIST_EMPTY (tags)))
- PrintEocDecoders (src, elmtLevel, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
else
PrintEocDecoders (src, elmtLevel-1, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
@@ -1345,16 +1335,6 @@
if ((builtinType == BASICTYPE_ANY) ||
(builtinType == BASICTYPE_ANYDEFINEDBY))
PrintEocDecoders (src, elmtLevel, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
- /*
- * must check for another EOC for tagged CHOICEs
- * since the choice decoder routines do not check
- * for an EOC on the choice's overall length -
- * they are only passed the tag/len of the choice's
- * component.
- */
- else if ((builtinType == BASICTYPE_CHOICE) &&
(!stoleChoiceTags) &&
- ((tags != NULL) && !LIST_EMPTY (tags)))
- PrintEocDecoders (src, elmtLevel, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
else
PrintEocDecoders (src, elmtLevel-1, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
@@ -1678,16 +1658,6 @@
if ((builtinType == BASICTYPE_ANY) ||
(builtinType == BASICTYPE_ANYDEFINEDBY))
PrintEocDecoders (src, elmtLevel, initialElmtLevel,
itemLenVarNameG,
totalLevel, decodedLenVarNameG);
- /*
- * must check for another EOC for tagged CHOICEs
- * since the choice decoder routines do not check
- * for an EOC on the choice's overall length -
- * they are only passed the tag/len of the choice's
- * component.
- */
- else if ((builtinType == BASICTYPE_CHOICE) && (!stoleChoiceTags) &&
- ((tags != NULL) && !LIST_EMPTY (tags)))
- PrintEocDecoders (src, elmtLevel, initialElmtLevel,
itemLenVarNameG,
totalLevel, decodedLenVarNameG);
else
PrintEocDecoders (src, elmtLevel-1, initialElmtLevel,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
@@ -1920,16 +1890,6 @@
if ((builtinType == BASICTYPE_ANY) ||
(builtinType == BASICTYPE_ANYDEFINEDBY))
PrintEocDecoders (src, elmtLevel, initialElmtLevel-1,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
- /*
- * must check for another EOC for tagged CHOICEs
- * since the choice decoder routines do not check
- * for an EOC on the choice's overall length -
- * they are only passed the tag/len of the choice's
- * component.
- */
- else if ((builtinType == BASICTYPE_CHOICE) &&
(!stoleChoiceTags) &&
- ((tags != NULL) && !LIST_EMPTY (tags)))
- PrintEocDecoders (src, elmtLevel, initialElmtLevel-1,
itemLenVarNameG, totalLevel, decodedLenVarNameG);
else
PrintEocDecoders (src, elmtLevel-1, initialElmtLevel-1,
itemLenVarNameG, totalLevel, decodedLenVarNameG);