Code review request: ASN.1 compiler support for large integers as 64-bit ints
Nico Williams <[email protected]>
| Newsgroups | gmane.comp.encryption.kerberos.heimdal.general |
|---|---|
| Message-ID | <CAK3OfOi=gf04DsQMDEFGBu4nYJyQOyY5E39ZJcM0nQAsa9n=jw@mail.gmail.com> |
Attached are patches for adding support to the Heimdal ASN.1 compiler for generating large C ints for INTEGER types with ranges small enough to fit in 64-bit integers. After I commit this I'll add support for BIT STRING with up to 64 named elements. This will become necessary eventually as we run out of HDBFlags. (It should also be possible to add support for BIT STRING with arbitrary numbers of named elements, but that would be significantly more work. 64 flags will do for a while.) Thanks, Nico --
asn1_large_ints.patch
(application/octet-stream, 27.6 KB)
From c7d8070fa1371039fd200b9264f1ffbb84364264 Mon Sep 17 00:00:00 2001 From: Nicolas Williams <[email protected]> Date: Wed, 22 Jun 2011 17:11:40 -0500 Subject: [PATCH 1/4] Initial 64-bit integer support for ASN.1 compiler. --- lib/asn1/asn1parse.y | 2 +- lib/asn1/der_copy.c | 14 +++++++++ lib/asn1/der_free.c | 12 ++++++++ lib/asn1/der_get.c | 45 +++++++++++++++++++++++++++-- lib/asn1/der_length.c | 57 +++++++++++++++++++++++++++++++++++++ lib/asn1/der_put.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ lib/asn1/gen.c | 20 +++++++------ lib/asn1/gen_decode.c | 18 ++++++----- lib/asn1/gen_encode.c | 12 ++++--- lib/asn1/gen_length.c | 12 ++++--- lib/asn1/gen_template.c | 22 ++++++++------ lib/asn1/lex.l | 2 +- lib/asn1/symbol.h | 10 ++++-- lib/hdb/hdb.asn1 | 1 + 14 files changed, 255 insertions(+), 44 deletions(-) diff --git a/lib/asn1/asn1parse.y b/lib/asn1/asn1parse.y index e3bea6c..7975429 100644 --- a/lib/asn1/asn1parse.y +++ b/lib/asn1/asn1parse.y @@ -69,7 +69,7 @@ struct string_list { %} %union { - int constant; + int64_t constant; struct value *value; struct range *range; char *name; diff --git a/lib/asn1/der_copy.c b/lib/asn1/der_copy.c index 3a0a8c5..87f1a0d 100644 --- a/lib/asn1/der_copy.c +++ b/lib/asn1/der_copy.c @@ -55,6 +55,13 @@ der_copy_integer (const int *from, int *to) } int +der_copy_integer64 (const int64_t *from, int64_t *to) +{ + *to = *from; + return 0; +} + +int der_copy_unsigned (const unsigned *from, unsigned *to) { *to = *from; @@ -62,6 +69,13 @@ der_copy_unsigned (const unsigned *from, unsigned *to) } int +der_copy_unsigned64 (const uint64_t *from, uint64_t *to) +{ + *to = *from; + return 0; +} + +int der_copy_generalized_time (const time_t *from, time_t *to) { *to = *from; diff --git a/lib/asn1/der_free.c b/lib/asn1/der_free.c index 4bae5fc..1584cfc 100644 --- a/lib/asn1/der_free.c +++ b/lib/asn1/der_free.c @@ -51,12 +51,24 @@ der_free_integer (int *i) } void +der_free_integer64 (int64_t *i) +{ + *i = 0; +} + +void der_free_unsigned (unsigned *u) { *u = 0; } void +der_free_unsigned64 (uint64_t *u) +{ + *u = 0; +} + +void der_free_generalized_time(time_t *t) { *t = 0; diff --git a/lib/asn1/der_get.c b/lib/asn1/der_get.c index 3112da8..8a456d4 100644 --- a/lib/asn1/der_get.c +++ b/lib/asn1/der_get.c @@ -48,9 +48,28 @@ der_get_unsigned (const unsigned char *p, size_t len, unsigned val = 0; size_t oldlen = len; - if (len == sizeof(unsigned) + 1 && p[0] == 0) + if (len == sizeof(val) + 1 && p[0] == 0) ; - else if (len > sizeof(unsigned)) + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int +der_get_unsigned64 (const unsigned char *p, size_t len, + uint64_t *ret, size_t *size) +{ + uint64_t val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && p[0] == 0) + ; + else if (len > sizeof(val)) return ASN1_OVERRUN; while (len--) @@ -67,7 +86,27 @@ der_get_integer (const unsigned char *p, size_t len, int val = 0; size_t oldlen = len; - if (len > sizeof(int)) + if (len > sizeof(val)) + return ASN1_OVERRUN; + + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int +der_get_integer64 (const unsigned char *p, size_t len, + int64_t *ret, size_t *size) +{ + int64_t val = 0; + size_t oldlen = len; + + if (len > sizeof(val)) return ASN1_OVERRUN; if (len > 0) { diff --git a/lib/asn1/der_length.c b/lib/asn1/der_length.c index db82025..684ba9b 100644 --- a/lib/asn1/der_length.c +++ b/lib/asn1/der_length.c @@ -56,6 +56,24 @@ _heim_len_unsigned (unsigned val) } size_t +_heim_len_unsigned64 (uint64_t val) +{ + size_t ret = 0; + int last_val_gt_128; + + do { + ++ret; + last_val_gt_128 = (val >= 128); + val /= 256; + } while (val); + + if(last_val_gt_128) + ret++; + + return ret; +} + +size_t _heim_len_int (int val) { unsigned char q; @@ -82,6 +100,33 @@ _heim_len_int (int val) return ret; } +size_t +_heim_len_int64 (int64_t val) +{ + unsigned char q; + size_t ret = 0; + + if (val >= 0) { + do { + q = val % 256; + ret++; + val /= 256; + } while(val); + if(q >= 128) + ret++; + } else { + val = ~val; + do { + q = ~(val % 256); + ret++; + val /= 256; + } while(val); + if(q < 128) + ret++; + } + return ret; +} + static size_t len_oid (const heim_oid *oid) { @@ -135,12 +180,24 @@ der_length_integer (const int *data) } size_t +der_length_integer64 (const int64_t *data) +{ + return _heim_len_int64 (*data); +} + +size_t der_length_unsigned (const unsigned *data) { return _heim_len_unsigned(*data); } size_t +der_length_unsigned64 (const uint64_t *data) +{ + return _heim_len_unsigned64(*data); +} + +size_t der_length_enumerated (const unsigned *data) { return _heim_len_int (*data); diff --git a/lib/asn1/der_put.c b/lib/asn1/der_put.c index 0b276d1..0ccb181 100644 --- a/lib/asn1/der_put.c +++ b/lib/asn1/der_put.c @@ -76,6 +76,38 @@ der_put_unsigned (unsigned char *p, size_t len, const unsigned *v, size_t *size) } int +der_put_unsigned64 (unsigned char *p, size_t len, const uint64_t *v, size_t *size) +{ + unsigned char *base = p; + uint64_t val = *v; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return ASN1_OVERFLOW; + else { + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + } + *size = base - p; + return 0; + } + } else if (len < 1) + return ASN1_OVERFLOW; + else { + *p = 0; + *size = 1; + return 0; + } +} + +int der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size) { unsigned char *base = p; @@ -115,6 +147,46 @@ der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size) return 0; } +int +der_put_integer64 (unsigned char *p, size_t len, const int64_t *v, size_t *size) +{ + unsigned char *base = p; + int64_t val = *v; + + if(val >= 0) { + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = val % 256; + len--; + val /= 256; + } while(val); + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = ~(val % 256); + len--; + val /= 256; + } while(val); + if(p[1] < 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + } + } + *size = base - p; + return 0; +} + int der_put_length (unsigned char *p, size_t len, size_t val, size_t *size) diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 2194b32..1c6a4ba 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -303,7 +303,7 @@ gen_assign_defval(const char *var, struct value *val) fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue); break; case integervalue: - fprintf(codefile, "%s = %d;\n", var, val->u.integervalue); + fprintf(codefile, "%s = %lld;\n", var, val->u.integervalue); break; case booleanvalue: if(val->u.booleanvalue) @@ -324,7 +324,7 @@ gen_compare_defval(const char *var, struct value *val) fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue); break; case integervalue: - fprintf(codefile, "if(%s != %d)\n", var, val->u.integervalue); + fprintf(codefile, "if(%s != %lld)\n", var, val->u.integervalue); break; case booleanvalue: if(val->u.booleanvalue) @@ -397,7 +397,7 @@ generate_constant (const Symbol *s) case booleanvalue: break; case integervalue: - fprintf (headerfile, "enum { %s = %d };\n\n", + fprintf (headerfile, "enum { %s = %lld };\n\n", s->gen_name, s->value->u.integervalue); break; case nullvalue: @@ -540,7 +540,7 @@ define_asn1 (int level, Type *t) if(t->members == NULL) { fprintf (headerfile, "INTEGER"); if (t->range) - fprintf (headerfile, " (%d..%d)", + fprintf (headerfile, " (%lld..%lld)", t->range->min, t->range->max); } else { Member *m; @@ -723,14 +723,16 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ fprintf (headerfile, "} %s;\n", name); } else if (t->range == NULL) { fprintf (headerfile, "heim_integer %s;\n", name); - } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) { + } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { + fprintf (headerfile, "int64_t %s;\n", name); + } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + fprintf (headerfile, "uint64_t %s;\n", name); + } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { fprintf (headerfile, "int %s;\n", name); - } else if (t->range->min == 0 && t->range->max == UINT_MAX) { - fprintf (headerfile, "unsigned int %s;\n", name); - } else if (t->range->min == 0 && t->range->max == INT_MAX) { + } else if (t->range->min >= 0 && t->range->max <= UINT_MAX) { fprintf (headerfile, "unsigned int %s;\n", name); } else - errx(1, "%s: unsupported range %d -> %d", + errx(1, "%s: unsupported range %lld -> %lld", name, t->range->min, t->range->max); break; case TBoolean: diff --git a/lib/asn1/gen_decode.c b/lib/asn1/gen_decode.c index 9d816d5..d845746 100644 --- a/lib/asn1/gen_decode.c +++ b/lib/asn1/gen_decode.c @@ -189,19 +189,19 @@ range_check(const char *name, { if (r->min == r->max + 2 || r->min < r->max) fprintf (codefile, - "if ((%s)->%s > %d) {\n" + "if ((%s)->%s > %lld) {\n" "e = ASN1_MAX_CONSTRAINT; %s;\n" "}\n", name, length, r->max, forwstr); if (r->min - 1 == r->max || r->min < r->max) fprintf (codefile, - "if ((%s)->%s < %d) {\n" + "if ((%s)->%s < %lld) {\n" "e = ASN1_MIN_CONSTRAINT; %s;\n" "}\n", name, length, r->min, forwstr); if (r->max == r->min) fprintf (codefile, - "if ((%s)->%s != %d) {\n" + "if ((%s)->%s != %lld) {\n" "e = ASN1_EXACT_CONSTRAINT; %s;\n" "}\n", name, length, r->min, forwstr); @@ -252,14 +252,16 @@ decode_type (const char *name, const Type *t, int optional, name); } else if (t->range == NULL) { decode_primitive ("heim_integer", name, forwstr); - } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) { + } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { + decode_primitive ("integer64", name, forwstr); + } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + decode_primitive ("unsigned64", name, forwstr); + } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { decode_primitive ("integer", name, forwstr); - } else if (t->range->min == 0 && t->range->max == UINT_MAX) { - decode_primitive ("unsigned", name, forwstr); - } else if (t->range->min == 0 && t->range->max == INT_MAX) { + } else if (t->range->min >= 0 && t->range->max <= UINT_MAX) { decode_primitive ("unsigned", name, forwstr); } else - errx(1, "%s: unsupported range %d -> %d", + errx(1, "%s: unsupported range %lld -> %lld", name, t->range->min, t->range->max); break; case TBoolean: diff --git a/lib/asn1/gen_encode.c b/lib/asn1/gen_encode.c index 1bd4748..0bdea8d 100644 --- a/lib/asn1/gen_encode.c +++ b/lib/asn1/gen_encode.c @@ -129,14 +129,16 @@ encode_type (const char *name, const Type *t, const char *tmpstr) fprintf(codefile, "}\n;"); } else if (t->range == NULL) { encode_primitive ("heim_integer", name); - } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) { + } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { + encode_primitive ("integer64", name); + } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + encode_primitive ("unsigned64", name); + } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { encode_primitive ("integer", name); - } else if (t->range->min == 0 && t->range->max == UINT_MAX) { - encode_primitive ("unsigned", name); - } else if (t->range->min == 0 && t->range->max == INT_MAX) { + } else if (t->range->min >= 0 && t->range->max <= UINT_MAX) { encode_primitive ("unsigned", name); } else - errx(1, "%s: unsupported range %d -> %d", + errx(1, "%s: unsupported range %lld -> %lld", name, t->range->min, t->range->max); constructed = 0; break; diff --git a/lib/asn1/gen_length.c b/lib/asn1/gen_length.c index 20b5adf..86bf6a6 100644 --- a/lib/asn1/gen_length.c +++ b/lib/asn1/gen_length.c @@ -80,14 +80,16 @@ length_type (const char *name, const Type *t, fprintf(codefile, "}\n"); } else if (t->range == NULL) { length_primitive ("heim_integer", name, variable); - } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) { + } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { + length_primitive ("integer64", name, variable); + } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + length_primitive ("unsigned64", name, variable); + } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { length_primitive ("integer", name, variable); - } else if (t->range->min == 0 && t->range->max == UINT_MAX) { - length_primitive ("unsigned", name, variable); - } else if (t->range->min == 0 && t->range->max == INT_MAX) { + } else if (t->range->min >= 0 && t->range->max <= UINT_MAX) { length_primitive ("unsigned", name, variable); } else - errx(1, "%s: unsupported range %d -> %d", + errx(1, "%s: unsupported range %lld -> %lld", name, t->range->min, t->range->max); break; diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index edd68e1..422a2e1 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -52,11 +52,13 @@ integer_symbol(const char *basename, const Type *t) return "int"; /* XXX enum foo */ else if (t->range == NULL) return "heim_integer"; - else if (t->range->min == INT_MIN && t->range->max == INT_MAX) + else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) + return "int64_t"; + else if (t->range->min >= 0 && t->range->max > INT_MAX) + return "uint64_t"; + else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) return "int"; - else if (t->range->min == 0 && t->range->max == UINT_MAX) - return "unsigned"; - else if (t->range->min == 0 && t->range->max == INT_MAX) + else if (t->range->min >= 0 && t->range->max <= UINT_MAX) return "unsigned"; else { abort(); @@ -490,14 +492,16 @@ template_members(struct templatehead *temp, const char *basetype, const char *na itype = "IMEMBER"; else if (t->range == NULL) itype = "HEIM_INTEGER"; - else if (t->range->min == INT_MIN && t->range->max == INT_MAX) + else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) + itype = "INTEGER64"; + else if (t->range->min >= 0 && t->range->max > INT_MAX) + itype = "UNSIGNED64"; + else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) itype = "INTEGER"; - else if (t->range->min == 0 && t->range->max == UINT_MAX) - itype = "UNSIGNED"; - else if (t->range->min == 0 && t->range->max == INT_MAX) + else if (t->range->min >= 0 && t->range->max <= UINT_MAX) itype = "UNSIGNED"; else - errx(1, "%s: unsupported range %d -> %d", + errx(1, "%s: unsupported range %lld -> %lld", name, t->range->min, t->range->max); add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset); diff --git a/lib/asn1/lex.l b/lib/asn1/lex.l index 2d32020..e72e5d9 100644 --- a/lib/asn1/lex.l +++ b/lib/asn1/lex.l @@ -255,7 +255,7 @@ WITH { return kw_WITH; } } -?0x[0-9A-Fa-f]+|-?[0-9]+ { char *e, *y = yytext; - yylval.constant = strtol((const char *)yytext, + yylval.constant = strtoll((const char *)yytext, &e, 0); if(e == y) lex_error_message("malformed constant (%s)", yytext); diff --git a/lib/asn1/symbol.h b/lib/asn1/symbol.h index a39c8f4..3a2d91b 100644 --- a/lib/asn1/symbol.h +++ b/lib/asn1/symbol.h @@ -78,7 +78,7 @@ struct value { } type; union { int booleanvalue; - int integervalue; + int64_t integervalue; char *stringvalue; struct objid *objectidentifiervalue; } u; @@ -109,8 +109,12 @@ struct tagtype { }; struct range { - int min; - int max; + /* + * We can't represent unsigned 64-bit ranges because max might be + * negative... + */ + int64_t min; + int64_t max; }; enum ctype { CT_CONTENTS, CT_USER } ; diff --git a/lib/hdb/hdb.asn1 b/lib/hdb/hdb.asn1 index 0594b31..faa58a9 100644 --- a/lib/hdb/hdb.asn1 +++ b/lib/hdb/hdb.asn1 @@ -118,6 +118,7 @@ HDB-extension ::= SEQUENCE { hist-kvno-diff-clnt[10] INTEGER (0..4294967295), hist-kvno-diff-svc[11] INTEGER (0..4294967295), policy[12] UTF8String, + principal-id[13] INTEGER(-9223372036854775808..9223372036854775807), ... }, ... -- 1.7.4.1 From a4853c5bc7015a4881ac56e46ecca77bb70ea870 Mon Sep 17 00:00:00 2001 From: Nicolas Williams <[email protected]> Date: Wed, 22 Jun 2011 18:11:43 -0500 Subject: [PATCH 2/4] Tests for unsigned 64-bit integer support in ASN.1 --- lib/asn1/check-gen.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/asn1/test.asn1 | 2 + 2 files changed, 62 insertions(+), 0 deletions(-) diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index e686f16..5f91238 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -765,6 +765,65 @@ check_tag_length(void) } static int +check_tag_length64(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 7, 7, "\x02\x05\x01\xff\xff\xff\xff"}, + { 1, 7, 7, "\x02\x05\x02\x00\x00\x00\x00"}, + { 1, 9, 9, "\x02\x07\x7f\xff\xff\xff\xff\xff\xff"}, + { 1, 10, 10, "\x02\x08\x00\x80\x00\x00\x00\x00\x00\x00"}, + { 1, 10, 10, "\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff"}, + { 1, 11, 11, "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTuint64 values[] = {0, 8589934591LL, 8589934592LL, + 36028797018963967LL, 36028797018963968LL, + 9223372036854775807LL, 18446744073709551615ULL, + 0, 127, 128, 256, 512 }; + TESTuint64 u; + int i, ret, failed = 0; + void *buf; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTuint64(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + printf("ret = %d\n", ret); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + printf("sz = %d\n", sz); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + printf("Expected value: %lld\nActual value: %lld\n", values[i], u); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int cmp_TESTChoice (void *a, void *b) { return 0; @@ -1291,6 +1350,7 @@ main(int argc, char **argv) ret += test_cert(); ret += check_tag_length(); + ret += check_tag_length64(); ret += test_large_tag(); ret += test_choice(); diff --git a/lib/asn1/test.asn1 b/lib/asn1/test.asn1 index 89154e3..9dfd28a 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -7,6 +7,8 @@ BEGIN IMPORTS heim_any FROM heim; TESTuint32 ::= INTEGER (0..4294967295) +TESTuint64 ::= INTEGER(0..18446744073709551615) +TESTint64 ::= INTEGER(-9223372036854775808..9223372036854775807) TESTLargeTag ::= SEQUENCE { foo[127] INTEGER (-2147483648..2147483647), -- 1.7.4.1 From 055d1b81ad7da5e37f84b468c5ddc1d843cf4c8c Mon Sep 17 00:00:00 2001 From: Nicolas Williams <[email protected]> Date: Thu, 23 Jun 2011 11:08:52 -0500 Subject: [PATCH 3/4] Added tests of coding of large negative 64-bit integers. --- lib/asn1/check-gen.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 60 insertions(+), 0 deletions(-) diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index 5f91238..44699ca 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -824,6 +824,65 @@ check_tag_length64(void) } static int +check_tag_length64s(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 7, 7, "\x02\x05\xfe\x00\x00\x00\x01"}, + { 1, 7, 7, "\x02\x05\xfe\x00\x00\x00\x00"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x01"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x00"}, + { 1, 10, 10, "\x02\x08\x80\x00\x00\x00\x00\x00\x00\x01"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x01"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTint64 values[] = {0, -8589934591LL, -8589934592LL, + -36028797018963967LL, -36028797018963968LL, + -9223372036854775807LL, -36028797018963967LL, + 0, 127, 128, 256, 512 }; + TESTint64 u; + int i, ret, failed = 0; + void *buf; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTint64(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + printf("ret = %d\n", ret); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + printf("sz = %d\n", sz); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + printf("Expected value: %lld\nActual value: %lld\n", values[i], u); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int cmp_TESTChoice (void *a, void *b) { return 0; @@ -1351,6 +1410,7 @@ main(int argc, char **argv) ret += check_tag_length(); ret += check_tag_length64(); + ret += check_tag_length64s(); ret += test_large_tag(); ret += test_choice(); -- 1.7.4.1 From 1b1eb209f4674ac2d7679ca3530cec9f3bc48577 Mon Sep 17 00:00:00 2001 From: Nicolas Williams <[email protected]> Date: Thu, 23 Jun 2011 11:09:44 -0500 Subject: [PATCH 4/4] Fixed a bug in 64-bit int support and a lesser old bug. The old bug was that the compiler treated INTEGER (0..4294967295) as signed int. You could see this by looking at the ASN.1 output in generated header files, where you'd see the ASN.1 type as INTEGER (0..2147483647), plus the C type as int instead of unsigned. All checks passed. --- lib/asn1/asn1parse.y | 4 ++-- lib/asn1/gen.c | 4 +++- lib/asn1/gen_decode.c | 2 +- lib/asn1/gen_encode.c | 2 +- lib/asn1/gen_length.c | 2 +- lib/asn1/gen_template.c | 4 ++-- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/asn1/asn1parse.y b/lib/asn1/asn1parse.y index 7975429..b419676 100644 --- a/lib/asn1/asn1parse.y +++ b/lib/asn1/asn1parse.y @@ -370,14 +370,14 @@ range : '(' Value RANGE Value ')' lex_error_message("Non-integer in first part of range"); $$ = ecalloc(1, sizeof(*$$)); $$->min = $2->u.integervalue; - $$->max = $2->u.integervalue - 1; + $$->max = INT_MAX; } | '(' kw_MIN RANGE Value ')' { if($4->type != integervalue) lex_error_message("Non-integer in second part of range"); $$ = ecalloc(1, sizeof(*$$)); - $$->min = $4->u.integervalue + 2; + $$->min = INT_MIN; $$->max = $4->u.integervalue; } | '(' Value ')' diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 1c6a4ba..f3129d1 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -724,8 +724,10 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ } else if (t->range == NULL) { fprintf (headerfile, "heim_integer %s;\n", name); } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { + fprintf(stderr, "Type %s will be an int64_t\n", name); fprintf (headerfile, "int64_t %s;\n", name); - } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + } else if (t->range->min >= 0 && t->range->max > UINT_MAX) { + fprintf(stderr, "Type %s will be a int64_t (t->range->max = %lld, UINT_MAX = %lld)\n", name, t->range->max, (int64_t)UINT_MAX); fprintf (headerfile, "uint64_t %s;\n", name); } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { fprintf (headerfile, "int %s;\n", name); diff --git a/lib/asn1/gen_decode.c b/lib/asn1/gen_decode.c index d845746..03890b0 100644 --- a/lib/asn1/gen_decode.c +++ b/lib/asn1/gen_decode.c @@ -254,7 +254,7 @@ decode_type (const char *name, const Type *t, int optional, decode_primitive ("heim_integer", name, forwstr); } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { decode_primitive ("integer64", name, forwstr); - } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + } else if (t->range->min >= 0 && t->range->max > UINT_MAX) { decode_primitive ("unsigned64", name, forwstr); } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { decode_primitive ("integer", name, forwstr); diff --git a/lib/asn1/gen_encode.c b/lib/asn1/gen_encode.c index 0bdea8d..1b9afc9 100644 --- a/lib/asn1/gen_encode.c +++ b/lib/asn1/gen_encode.c @@ -131,7 +131,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr) encode_primitive ("heim_integer", name); } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { encode_primitive ("integer64", name); - } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + } else if (t->range->min >= 0 && t->range->max > UINT_MAX) { encode_primitive ("unsigned64", name); } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { encode_primitive ("integer", name); diff --git a/lib/asn1/gen_length.c b/lib/asn1/gen_length.c index 86bf6a6..b815f1a 100644 --- a/lib/asn1/gen_length.c +++ b/lib/asn1/gen_length.c @@ -82,7 +82,7 @@ length_type (const char *name, const Type *t, length_primitive ("heim_integer", name, variable); } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { length_primitive ("integer64", name, variable); - } else if (t->range->min >= 0 && t->range->max > INT_MAX) { + } else if (t->range->min >= 0 && t->range->max > UINT_MAX) { length_primitive ("unsigned64", name, variable); } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { length_primitive ("integer", name, variable); diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index 422a2e1..e810504 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -54,7 +54,7 @@ integer_symbol(const char *basename, const Type *t) return "heim_integer"; else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) return "int64_t"; - else if (t->range->min >= 0 && t->range->max > INT_MAX) + else if (t->range->min >= 0 && t->range->max > UINT_MAX) return "uint64_t"; else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) return "int"; @@ -494,7 +494,7 @@ template_members(struct templatehead *temp, const char *basetype, const char *na itype = "HEIM_INTEGER"; else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) itype = "INTEGER64"; - else if (t->range->min >= 0 && t->range->max > INT_MAX) + else if (t->range->min >= 0 && t->range->max > UINT_MAX) itype = "UNSIGNED64"; else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) itype = "INTEGER"; -- 1.7.4.1