diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index b481e1d14..9e5f086db 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -763,6 +763,27 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ Member *m; Type i; struct range range = { 0, UINT_MAX }; + size_t max_memno = 0; + size_t bitset_size; + + /* + * range.max implies the size of the base unsigned integer used for the + * bitfield members. If it's less than or equal to UINT_MAX, then that + * will be unsigned int, otherwise it will be uint64_t. + * + * We could just use uint64_t, yes, but for now, and in case that any + * projects were exposing the BIT STRING types' C representations in + * ABIs prior to this compiler supporting BIT STRING with larger + * members, we stick to this. + */ + ASN1_TAILQ_FOREACH(m, t->members, members) { + if (m->val > max_memno) + max_memno = m->val; + } + if (max_memno > 63) + range.max = INT64_MAX; + else + range.max = 1LU << max_memno; i.type = TInteger; i.range = ⦥ @@ -780,10 +801,13 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ ASN1_TAILQ_FOREACH(m, t->members, members) { char *n = NULL; - /* pad unused */ + /* + * pad unused bits beween declared members (hopefully this + * forces the compiler to give us an obvious layout) + */ while (pos < m->val) { if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL) - errx(1, "malloc"); + err(1, "malloc"); define_type (level + 1, n, newbasename, &i, FALSE, FALSE); free(n); pos++; @@ -797,8 +821,13 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ n = NULL; pos++; } - /* pad to 32 elements */ - while (pos < 32) { + /* pad unused tail (ditto) */ + bitset_size = max_memno; + if (max_memno > 31) + bitset_size += 64 - (max_memno % 64); + else + bitset_size = 32; + while (pos < bitset_size) { char *n = NULL; if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL) errx(1, "malloc"); diff --git a/lib/asn1/gen_decode.c b/lib/asn1/gen_decode.c index 650017fa6..6c9f6e5aa 100644 --- a/lib/asn1/gen_decode.c +++ b/lib/asn1/gen_decode.c @@ -354,7 +354,7 @@ decode_type (const char *name, const Type *t, int optional, break; fprintf(codefile, "{\n"); - fprintf(codefile, "unsigned int members = 0;\n"); + fprintf(codefile, "uint64_t members = 0;\n"); fprintf(codefile, "while(len > 0) {\n"); fprintf(codefile, "Der_class class;\n" @@ -384,7 +384,7 @@ decode_type (const char *name, const Type *t, int optional, decode_type (s, m->type, 0, forwstr, m->gen_name, NULL, depth + 1); free (s); - fprintf(codefile, "members |= (1 << %d);\n", memno); + fprintf(codefile, "members |= (1LU << %u);\n", memno); memno++; fprintf(codefile, "break;\n"); } @@ -400,7 +400,7 @@ decode_type (const char *name, const Type *t, int optional, if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL) errx(1, "malloc"); - fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno); + fprintf(codefile, "if((members & (1LU << %u)) == 0)\n", memno); if(m->optional) fprintf(codefile, "%s = NULL;\n", s); else if(m->defval) diff --git a/lib/asn1/gen_glue.c b/lib/asn1/gen_glue.c index 773ce787d..a7d90e368 100644 --- a/lib/asn1/gen_glue.c +++ b/lib/asn1/gen_glue.c @@ -43,17 +43,17 @@ generate_2int (const Type *t, const char *gen_name) Member *m; fprintf (headerfile, - "unsigned %s2int(%s);\n", + "uint64_t %s2int(%s);\n", gen_name, gen_name); fprintf (codefile, - "unsigned %s2int(%s f)\n" + "uint64_t %s2int(%s f)\n" "{\n" - "unsigned r = 0;\n", + "uint64_t r = 0;\n", gen_name, gen_name); ASN1_TAILQ_FOREACH(m, t->members, members) { - fprintf (codefile, "if(f.%s) r |= (1U << %d);\n", + fprintf (codefile, "if(f.%s) r |= (1LU << %d);\n", m->gen_name, m->val); } fprintf (codefile, "return r;\n" @@ -66,11 +66,11 @@ generate_int2 (const Type *t, const char *gen_name) Member *m; fprintf (headerfile, - "%s int2%s(unsigned);\n", + "%s int2%s(uint64_t);\n", gen_name, gen_name); fprintf (codefile, - "%s int2%s(unsigned n)\n" + "%s int2%s(uint64_t n)\n" "{\n" "\t%s flags;\n\n" "\tmemset(&flags, 0, sizeof(flags));\n\n", @@ -114,7 +114,7 @@ generate_units (const Type *t, const char *gen_name) if(t->members) { ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { fprintf (codefile, - "\t{\"%s\",\t1U << %d},\n", m->name, m->val); + "\t{\"%s\",\t1LU << %d},\n", m->name, m->val); } } @@ -143,14 +143,21 @@ generate_glue (const Type *t, const char *gen_name) case TTag: generate_glue(t->subtype, gen_name); break; - case TBitString : - if (!ASN1_TAILQ_EMPTY(t->members)) { - generate_2int (t, gen_name); - generate_int2 (t, gen_name); - if (parse_units_flag) - generate_units (t, gen_name); - } + case TBitString : { + Member *m; + + if (ASN1_TAILQ_EMPTY(t->members)) + break; + ASN1_TAILQ_FOREACH(m, t->members, members) { + if (m->val > 63) + return; + } + generate_2int (t, gen_name); + generate_int2 (t, gen_name); + if (parse_units_flag) + generate_units (t, gen_name); break; + } default : break; } diff --git a/lib/asn1/test.asn1 b/lib/asn1/test.asn1 index 3b70a02cd..7546ed744 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -188,6 +188,21 @@ TESTBitString ::= BIT STRING { thirtyone(31) } +TESTBitString64 ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31), + thirtytwo(32), + sixtythree(63) +} + +TESTLargeBitString ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31), + onehundredtwenty(120) +} + TESTMechType::= OBJECT IDENTIFIER TESTMechTypeList ::= SEQUENCE OF TESTMechType diff --git a/lib/roken/parse_units.h b/lib/roken/parse_units.h index 636690595..0cb5f5a9a 100644 --- a/lib/roken/parse_units.h +++ b/lib/roken/parse_units.h @@ -51,7 +51,7 @@ struct units { const char *name; - unsigned mult; + unsigned long long mult; }; ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL