[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);