From 1d03669d1bd93034edc8688033550254ca0f90e0 Mon Sep 17 00:00:00 2001 From: vlm Date: Thu, 19 Aug 2004 13:29:46 +0000 Subject: [PATCH] constraint checking code git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@149 59561ff5-6e30-0410-9f3c-9617f08c8826 --- libasn1compiler/Makefile.am | 2 + libasn1compiler/Makefile.in | 8 +- libasn1compiler/asn1c_C.c | 712 +---------------------------- libasn1compiler/asn1c_constraint.c | 482 +++++++++++++++++++ libasn1compiler/asn1c_constraint.h | 7 + libasn1compiler/asn1c_internal.h | 2 +- 6 files changed, 508 insertions(+), 705 deletions(-) create mode 100644 libasn1compiler/asn1c_constraint.c create mode 100644 libasn1compiler/asn1c_constraint.h diff --git a/libasn1compiler/Makefile.am b/libasn1compiler/Makefile.am index ef96aef9..bcfaf93d 100644 --- a/libasn1compiler/Makefile.am +++ b/libasn1compiler/Makefile.am @@ -13,7 +13,9 @@ libasn1compiler_la_SOURCES = \ asn1c_lang.c asn1c_lang.h \ asn1c_save.c asn1c_save.h \ asn1c_C.c asn1c_C.h \ + asn1c_constraint.c asn1c_constraint.h \ asn1c_compat.c asn1c_compat.h \ + asn1c_fdeps.c asn1c_fdeps.h \ asn1c_internal.h TESTS = $(check_PROGRAMS) diff --git a/libasn1compiler/Makefile.in b/libasn1compiler/Makefile.in index e8153937..b427be97 100644 --- a/libasn1compiler/Makefile.in +++ b/libasn1compiler/Makefile.in @@ -53,7 +53,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) libasn1compiler_la_LIBADD = am_libasn1compiler_la_OBJECTS = asn1compiler.lo asn1c_misc.lo \ asn1c_out.lo asn1c_lang.lo asn1c_save.lo asn1c_C.lo \ - asn1c_compat.lo + asn1c_constraint.lo asn1c_compat.lo asn1c_fdeps.lo libasn1compiler_la_OBJECTS = $(am_libasn1compiler_la_OBJECTS) check_compiler_SOURCES = check_compiler.c check_compiler_OBJECTS = check_compiler.$(OBJEXT) @@ -66,6 +66,8 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/asn1c_C.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/asn1c_compat.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_constraint.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/asn1c_fdeps.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/asn1c_lang.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/asn1c_misc.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/asn1c_out.Plo \ @@ -208,7 +210,9 @@ libasn1compiler_la_SOURCES = \ asn1c_lang.c asn1c_lang.h \ asn1c_save.c asn1c_save.h \ asn1c_C.c asn1c_C.h \ + asn1c_constraint.c asn1c_constraint.h \ asn1c_compat.c asn1c_compat.h \ + asn1c_fdeps.c asn1c_fdeps.h \ asn1c_internal.h TESTS = $(check_PROGRAMS) @@ -279,6 +283,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_C.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_compat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_constraint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_fdeps.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_lang.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_misc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn1c_out.Plo@am__quote@ diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c index 197ce1f9..ac138733 100644 --- a/libasn1compiler/asn1c_C.c +++ b/libasn1compiler/asn1c_C.c @@ -4,7 +4,8 @@ */ #include "asn1c_internal.h" #include "asn1c_C.h" -#include /* exportable stuff from libasn1fix */ +#include "asn1c_constraint.h" +#include /* Stuff exported by libasn1fix */ typedef struct tag2el_s { struct asn1p_type_tag_s el_tag; @@ -25,17 +26,6 @@ static int _print_tag(arg_t *arg, asn1p_expr_t *expr, struct asn1p_type_tag_s *t static int check_if_extensible(asn1p_expr_t *expr); static int emit_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice_mode); static int emit_tag2member_map(arg_t *arg, tag2el_t *tag2el, int tag2el_count); -static int emit_constraint_checking_code(arg_t *arg); -static int emit_single_constraint_check(arg_t *arg, asn1p_constraint_t *ct, int mode); -static int emit_alphabet_tables(arg_t *arg, asn1p_constraint_t *ct, int *table); -static int emit_alphabet_check_cycle(arg_t *arg); -static int check_constraint_type_presence(asn1p_constraint_t *ct, enum asn1p_constraint_type_e type); -static asn1p_expr_type_e _find_terminal_type(arg_t *arg); -static int emit_value_determination_code(arg_t *arg); -static int emit_size_determination_code(arg_t *arg); -static long compute_min_size(arg_t *arg); -static long compute_max_size(arg_t *arg); -static long compute_xxx_size(arg_t *arg, int _max); #define C99_MODE (arg->flags & A1C_NO_C99) #define UNNAMED_UNIONS (arg->flags & A1C_UNNAMED_UNIONS) @@ -969,28 +959,28 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { /* * Constraint checking. */ - if(expr->constraints) /* Emit tables with FROM() constraints */ - emit_alphabet_tables(arg, expr->constraints, 0); + /* Emit FROM() tables and others */ + asn1c_emit_constraint_tables(arg, 0); + p = MKID(expr->Identifier); OUT("int\n"); OUT("%s_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,\n", p); INDENTED( OUT("\t\tasn_app_consume_bytes_f *app_errlog, void *app_key) {\n"); OUT("\n"); - if(expr->constraints) { - - emit_constraint_checking_code(arg); - + if(asn1c_emit_constraint_checking_code(arg) == 1) { + if(0) { OUT("/* Check the constraints of the underlying type */\n"); OUT("return asn1_DEF_%s.check_constraints\n", asn1c_type_name(arg, expr, TNF_SAFE)); OUT("\t(td, sptr, app_errlog, app_key);\n"); - } else { + } else { OUT("/* Make the underlying type checker permanent */\n"); OUT("td->check_constraints = asn1_DEF_%s.check_constraints;\n", asn1c_type_name(arg, expr, TNF_SAFE)); OUT("return td->check_constraints\n"); OUT("\t(td, sptr, app_errlog, app_key);\n"); + } } ); OUT("}\n"); @@ -1365,687 +1355,3 @@ emit_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice return tags_count; } - -static int -emit_constraint_checking_code(arg_t *arg) { - asn1p_expr_t *expr = arg->expr; - asn1p_expr_type_e etype; - int size_present, value_present; - - if(expr->constraints == NULL) - return 0; /* No constraints defined */ - - etype = _find_terminal_type(arg); - - size_present = check_constraint_type_presence(expr->constraints, - ACT_CT_SIZE); - value_present = check_constraint_type_presence(expr->constraints, - ACT_EL_VALUE); - - if(size_present || value_present) { - OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier)); - if(size_present) { - OUT("size_t size;\n"); - OUT("size_t min_size __attribute__ ((unused)) = %ld;\n", - compute_min_size(arg)); - OUT("size_t max_size __attribute__ ((unused)) = %ld;\n", - compute_max_size(arg)); - } - if(value_present) - switch(etype) { - case ASN_BASIC_INTEGER: - case ASN_BASIC_ENUMERATED: - OUT("long value;\n"); - break; - case ASN_BASIC_BOOLEAN: - OUT("int value;\n"); - break; - default: - break; - } - OUT("\n"); - } - - OUT("if(!sptr) {\n"); - INDENT(+1); - OUT("_ASN_ERRLOG(app_errlog, app_key,\n"); - OUT("\t\"%%s: value not given\", td->name);\n"); - OUT("return -1;\n"); - INDENT(-1); - OUT("}\n"); - OUT("\n"); - - if(size_present) - emit_size_determination_code(arg); - if(value_present) - emit_value_determination_code(arg); - - OUT("\n"); - OUT("if(\n"); - emit_single_constraint_check(arg, expr->constraints, 0); - OUT(") {\n"); - INDENTED(OUT("/* Constraint check succeeded */\n")); - OUT("} else {\n"); - INDENT(+1); - OUT("_ASN_ERRLOG(app_errlog, app_key,\n"); - OUT("\t\"%%s: constraint failed\", td->name);\n"); - OUT("return -1;\n"); - INDENT(-1); - OUT("}\n"); - - return 0; -} - -static int -emit_single_constraint_check(arg_t *arg, asn1p_constraint_t *ct, int mode) { - char *s_v; - int el; - - assert(arg && ct); - - switch(ct->type) { - case ACT_INVALID: - assert(ct->type != ACT_INVALID); - OUT("-1 /* Invalid constraint at line %d */\n", ct->_lineno); - break; - case ACT_EL_VALUE: - OUT("("); - if(mode == ACT_CT_SIZE) s_v = "size"; - else s_v = "value"; - OUT("%s", s_v); - if(ct->value->type != ATV_TRUE) - OUT(" == "); - switch(ct->value->type) { - case ATV_INTEGER: OUT("%lld", - (long long)ct->value->value.v_integer); break; - case ATV_MIN: OUT("min_%s", s_v); break; - case ATV_MAX: OUT("max_%s", s_v); break; - case ATV_FALSE: OUT("0"); break; - case ATV_TRUE: break; - default: - break; - } - OUT(")\n"); - break; - case ACT_EL_RANGE: - case ACT_EL_LLRANGE: - case ACT_EL_RLRANGE: - case ACT_EL_ULRANGE: - if(mode == ACT_CT_SIZE) { - s_v = "size"; - } else { - s_v = "value"; - } - OUT("((%s", s_v); - switch(ct->type) { - case ACT_EL_RANGE: - case ACT_EL_RLRANGE: - OUT(" >= "); break; - case ACT_EL_LLRANGE: - case ACT_EL_ULRANGE: - OUT(" > "); break; - default: break; - } - switch(ct->range_start->type) { - case ATV_INTEGER: OUT("%lld", - (long long)ct->range_start->value.v_integer); break; - case ATV_MIN: OUT("min_%s", s_v); break; - case ATV_MAX: OUT("max_%s", s_v); break; - case ATV_FALSE: OUT("0"); break; - case ATV_TRUE: break; - default: - break; - } - OUT(") && (%s", s_v); - switch(ct->type) { - case ACT_EL_RANGE: - case ACT_EL_LLRANGE: - OUT(" <= "); break; - case ACT_EL_RLRANGE: - case ACT_EL_ULRANGE: - OUT(" < "); break; - default: break; - } - switch(ct->range_stop->type) { - case ATV_INTEGER: OUT("%lld", - (long long)ct->range_stop->value.v_integer); break; - case ATV_MIN: OUT("min_%s", s_v); break; - case ATV_MAX: OUT("max_%s", s_v); break; - case ATV_FALSE: OUT("0"); break; - case ATV_TRUE: break; - default: - break; - } - OUT("))\n"); - break; - case ACT_EL_EXT: - OUT("0 /* Extensible (...), but not defined herein */\n"); - break; - case ACT_CT_SIZE: - if(mode) { - OUT("0 /* Invalid constraint at line %d */\n", - ct->_lineno); - return -1; - } - assert(ct->el_count == 1); - return emit_single_constraint_check(arg, - ct->elements[0], ACT_CT_SIZE); - case ACT_CT_FROM: - if(mode) { - OUT("0 /* Invalid constraint at line %d */\n", - ct->_lineno); - return -1; - } - OUT("check_alphabet_%x(sptr)\n", ct); - break; - case ACT_CT_WCOMP: - case ACT_CT_WCOMPS: - OUT("%d /* Unsupported constraint at line %d */\n", - ct->type, ct->_lineno); - return -1; - break; - case ACT_CA_SET: - OUT("(\n"); - INDENT(+1); - for(el = 0; el < ct->el_count; el++) { - if(el) OUT("&& "); - emit_single_constraint_check(arg, - ct->elements[el], mode); - } - INDENT(-1); - OUT(")\n"); - break; - case ACT_CA_CSV: - OUT("(\n"); - INDENT(+1); - for(el = 0; el < ct->el_count; el++) { - if(el) OUT("|| "); - emit_single_constraint_check(arg, - ct->elements[el], mode); - } - INDENT(-1); - OUT(")\n"); - break; - case ACT_CA_UNI: - OUT("(\n"); - INDENT(+1); - for(el = 0; el < ct->el_count; el++) { - if(el) OUT("|| "); - emit_single_constraint_check(arg, - ct->elements[el], mode); - } - INDENT(-1); - OUT(")\n"); - break; - case ACT_CA_INT: - OUT("(\n"); - INDENT(+1); - for(el = 0; el < ct->el_count; el++) { - if(el) OUT("&& "); - emit_single_constraint_check(arg, - ct->elements[el], mode); - } - INDENT(-1); - OUT(")\n"); - break; - case ACT_CA_CRC: - WARNING("Unsupported component relation constraint at line %d", - ct->_lineno); - OUT("%d /* Unsupported component relation constraint " - "at line %d */\n", - ct->type, ct->_lineno); - return -1; - case ACT_CA_EXC: - WARNING("Unsupported EXCEPT constraint at line %d", - ct->_lineno); - OUT("%d /* Unsupported EXCEPT constraint at line %d */\n", - ct->type, ct->_lineno); - return -1; - } - - return 0; -} - -static int -check_constraint_type_presence(asn1p_constraint_t *ct, enum asn1p_constraint_type_e type) { - int el; - - if(ct == NULL) return 0; - - if(ct->type == type) return 1; - - if(type == ACT_EL_VALUE) { - if(ct->type >= ACT_CT_SIZE - && ct->type <= ACT_CT_WCOMPS) - /* Values defined further - * are not really value's values */ - return 0; - if(ct->type > ACT_EL_VALUE && ct->type < ACT_CT_SIZE) - return 1; /* Also values */ - } - - for(el = 0; el < ct->el_count; el++) { - if(check_constraint_type_presence(ct->elements[el], type)) - return 1; - } - - return 0; -} - -static int -emit_alphabet_tables(arg_t *arg, asn1p_constraint_t *ct, int *table) { - int ch = 0; - int ch_start = 0; - int ch_stop = 0; - int el = 0; - - assert(arg && ct); - - switch(ct->type) { - case ACT_INVALID: - break; - case ACT_EL_VALUE: - if(!table) break; - - switch(ct->value->type) { - case ATV_INTEGER: - if(ct->value->value.v_integer < 0 - || ct->value->value.v_integer > 255) { - OUT("\n"); - OUT("#error Value %lld out of range " - "for alphabet character at line %d\n", - (long long)ct->value->value.v_integer, - ct->_lineno); - break; - } else { - ch = ct->value->value.v_integer; - table[ch] = 1; - } - break; - case ATV_STRING: - for(ch = 0; ch < ct->value->value.string.size; ch++) - table[ct->value->value.string.buf[ch]] = 1; - break; - default: - OUT("\n"); - WARNING("Invalid alphabet character specification " - "at line %d", ct->_lineno); - OUT("#error Invalid alphabet character specification " - "at line %d\n", ct->_lineno); - break; - } - break; - case ACT_EL_RANGE: - case ACT_EL_LLRANGE: - case ACT_EL_RLRANGE: - case ACT_EL_ULRANGE: - if(!table) break; - - ch_start = 0; - ch_stop = 255; - - switch(ct->range_start->type) { - case ATV_INTEGER: - ch_start = ct->range_start->value.v_integer; break; - case ATV_MIN: ch_start = 0; break; - case ATV_MAX: ch_start = 255; break; - case ATV_STRING: - if(ct->range_start->value.string.size == 1) { - ch_start = ct->range_start->value.string.buf[0]; - break; - } - /* Fall through */ - default: - OUT("\n"); - FATAL("Invalid alphabet range constraint " - "at line %d\n", ct->_lineno); - OUT("#error Invalid alphabet range constraint " - "at line %d\n", ct->_lineno); - return -1; - } - - switch(ct->range_stop->type) { - case ATV_INTEGER: - ch_stop = ct->range_stop->value.v_integer; break; - case ATV_MIN: ch_stop = 0; break; - case ATV_MAX: ch_stop = 255; break; - case ATV_STRING: - if(ct->range_stop->value.string.size == 1) { - ch_stop = ct->range_stop->value.string.buf[0]; - break; - } - /* Fall through */ - default: - OUT("\n"); - FATAL("Invalid alphabet range constraint " - "at line %d\n", ct->_lineno); - OUT("#error Invalid alphabet range constraint " - "at line %d\n", ct->_lineno); - break; - } - - switch(ct->type) { - case ACT_EL_RANGE: break; - case ACT_EL_RLRANGE: ch_stop--; break; - case ACT_EL_LLRANGE: ch_start++; break; - case ACT_EL_ULRANGE: ch_start++; ch_stop--; break; - default: break; - } - - if(ch_start > ch_stop) { - WARNING("Empty character range " - "alphabet constraint at line %d", ct->_lineno); - OUT_NOINDENT("#warning Empty character range " - "alphabet constraint at line %d\n", ct->_lineno); - break; - } - - for(ch = ch_start; ch <= ch_stop; ch++) { - if(ch < 0 || ch > 255) continue; - table[ch] = 1; - } - - break; - case ACT_EL_EXT: - break; - case ACT_CT_SIZE: - break; - case ACT_CT_FROM: - if(table) { - OUT("#error Nested FROM in subtype constraints\n"); - return -1; - } else { - table = alloca(256 * sizeof(table[0])); - memset(table, 0, 256 * sizeof(table[0])); - - for(el = 0; el < ct->el_count; el++) { - emit_alphabet_tables(arg, ct->elements[el], - table); - } - OUT("static int alphabet_table_%x[256] = {\n", ct); - for(ch = 0; ch < 256; ch++) { - OUT("%d,", table[ch]?1:0); - if(!((ch+1) % 16)) { - if(ch) { - int c; - OUT("\t/* "); - for(c = ch - 16; c < ch; c++) { - if(table[c]) { - if(c > 0x20 - && c < 0x80) - OUT("%c", c); - else - OUT(".", c); - } else { - OUT(" "); - } - } - OUT(" */"); - } - OUT("\n"); - } - } - OUT("};\n"); - OUT("static int check_alphabet_%x(const void *sptr) {\n", ct); - INDENT(+1); - OUT("int *table = alphabet_table_%x;\n", ct); - emit_alphabet_check_cycle(arg); - OUT("return 1;\n"); - INDENT(-1); - OUT("};\n"); - } - break; - case ACT_CT_WCOMP: - case ACT_CT_WCOMPS: - break; - case ACT_CA_CRC: - break; - case ACT_CA_SET: - case ACT_CA_CSV: - case ACT_CA_UNI: - for(el = 0; el < ct->el_count; el++) - emit_alphabet_tables(arg, ct->elements[el], table); - break; - case ACT_CA_INT: - if(table) { - int table2[256]; - - assert(ct->el_count >= 1); - emit_alphabet_tables(arg, ct->elements[0], table); - for(el = 1; el < ct->el_count; el++) { - memset(table2, 0, sizeof(table2)); - emit_alphabet_tables(arg, - ct->elements[el], table2); - /* Intersection */ - for(ch = 0; ch < 256; ch++) { - if(table2[ch] == 0) - table[ch] = 0; - } - } - } else { - for(el = 0; el < ct->el_count; el++) - emit_alphabet_tables(arg, ct->elements[el], 0); - } - - break; - case ACT_CA_EXC: - OUT("EXC\n"); - if(table) { - int table2[256]; - - assert(ct->el_count >= 1); - emit_alphabet_tables(arg, ct->elements[0], table); - for(el = 1; el < ct->el_count; el++) { - memset(table2, 0, sizeof(table2)); - emit_alphabet_tables(arg, - ct->elements[el], table2); - /* Exclusion */ - for(ch = 0; ch < 256; ch++) { - if(table2[ch]) - table[ch] = 0; - } - } - } else { - for(el = 0; el < ct->el_count; el++) - emit_alphabet_tables(arg, ct->elements[el], 0); - } - break; - } - - return 0; -} - -static int -emit_alphabet_check_cycle(arg_t *arg) { - asn1p_expr_type_e etype; - - etype = _find_terminal_type(arg); - if(!(etype & ASN_STRING_MASK) - && !(etype == ASN_BASIC_OCTET_STRING)) { - OUT("#error Cannot apply FROM constraint to ASN.1 type %s\n", - ASN_EXPR_TYPE2STR(etype)); - return -1; - } - - OUT("/* The underlying type is %s */\n", - ASN_EXPR_TYPE2STR(etype)); - OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier)); - - switch(etype) { - case ASN_STRING_UTF8String: - OUT("uint8_t *ch = st->buf;\n"); - OUT("uint8_t *end = ch + st->size;\n"); - OUT("\n"); - OUT("for(; ch < end; ch++) {\n"); - INDENT(+1); - OUT("if(*ch >= 0x80 || !table[*ch]) return 0;\n"); - INDENT(-1); - OUT("}\n"); - break; - case ASN_STRING_UniversalString: - OUT("uint32_t *ch = st->buf;\n"); - OUT("uint32_t *end = ch + st->size;\n"); - OUT("\n"); - OUT("for(; ch < end; ch++) {\n"); - INDENT(+1); - OUT("uint32_t wc = (((uint8_t *)ch)[0] << 24)\n"); - OUT("\t\t| (((uint8_t *)ch)[1] << 16)\n"); - OUT("\t\t| (((uint8_t *)ch)[2] << 8)\n"); - OUT("\t\t| ((uint8_t *)ch)[3]\n"); - OUT("if(wc > 255 || !table[wc]) return 0;\n"); - INDENT(-1); - OUT("}\n"); - OUT("if(ch != end) return 0; /* (size%4)! */\n"); - break; - case ASN_STRING_BMPString: - OUT("uint16_t *ch = st->buf;\n"); - OUT("uint16_t *end = ch + st->size;\n"); - OUT("\n"); - OUT("for(; ch < end; ch++) {\n"); - INDENT(+1); - OUT("uint16_t wc = (((uint8_t *)ch)[0] << 8)\n"); - OUT("\t\t| ((uint8_t *)ch)[1];\n"); - OUT("if(wc > 255 || !table[wc]) return 0;\n"); - INDENT(-1); - OUT("}\n"); - OUT("if(ch != end) return 0; /* (size%2)! */\n"); - break; - case ASN_BASIC_OCTET_STRING: - default: - OUT("uint8_t *ch = st->buf;\n"); - OUT("uint8_t *end = ch + st->size;\n"); - OUT("\n"); - OUT("for(; ch < end; ch++) {\n"); - INDENT(+1); - OUT("if(!table[*ch]) return 0;\n"); - INDENT(-1); - OUT("}\n"); - break; - } - - return 0; -} - -static int -emit_size_determination_code(arg_t *arg) { - asn1p_expr_type_e etype = _find_terminal_type(arg); - - switch(etype) { - case ASN_BASIC_BIT_STRING: - OUT("if(st->size > 0) {\n"); - OUT("\t/* Size in bits */\n"); - OUT("\tsize = (st->size - 1) - (st->buf[0] & 0x7);\n"); - OUT("} else {\n"); - OUT("\tsize = 0;\n"); - OUT("}\n"); - break; - case ASN_STRING_UniversalString: - OUT("size = st->size >> 2;\t/* 4 byte per character */\n"); - break; - case ASN_STRING_BMPString: - OUT("size = st->size >> 1;\t/* 2 byte per character */\n"); - break; - case ASN_STRING_UTF8String: - OUT("size = UTF8String_length(st, td->name, app_errlog, app_key);\n"); - OUT("if(size == (size_t)-1) return -1;\n"); - break; - default: - if((etype & ASN_STRING_MASK) - || etype == ASN_BASIC_OCTET_STRING) { - OUT("size = st->size;\n"); - break; - } else { - const char *type_name = ASN_EXPR_TYPE2STR(etype); - if(!type_name) type_name = arg->expr->Identifier; - WARNING("SIZE constraint is not defined for %s", - type_name); - OUT_NOINDENT("#warning SIZE constraint " - "not defined for %s!\n", type_name); - OUT("size = st->size;\n"); - } - return -1; - } - - return 0; -} - -static int -emit_value_determination_code(arg_t *arg) { - asn1p_expr_type_e etype = _find_terminal_type(arg); - - switch(etype) { - case ASN_BASIC_INTEGER: - case ASN_BASIC_ENUMERATED: - if(arg->flags & A1C_USE_NATIVE_INTEGERS) { - OUT("value = *(int *)st;\n"); - } else { - OUT("if(asn1_INTEGER2long(st, &value)) {\n"); - INDENT(+1); - OUT("_ASN_ERRLOG(app_errlog, app_key,\n"); - OUT("\t\"%%s: value too large\", td->name);\n"); - OUT("return -1;\n"); - INDENT(-1); - OUT("}\n"); - } - break; - case ASN_BASIC_BOOLEAN: - OUT("value = st->value;\n"); - break; - default: - WARNING("Value cannot be determined " - "for constraint check for %s at line %d\n", - arg->expr->Identifier, arg->expr->_lineno); - OUT("#error Value cannot be determined for %s at %d\n", - arg->expr->Identifier, arg->expr->_lineno); - break; - } - - return 0; -} - -static long compute_min_size(arg_t *arg) { return compute_xxx_size(arg, 0); } -static long compute_max_size(arg_t *arg) { return compute_xxx_size(arg, 1); } - -static long compute_xxx_size(arg_t *arg, int _max) { - asn1p_expr_type_e etype; - long basic_max = 0x7fffffff; - long basic_min = 0x80000000; - long svalue = 0; - - etype = _find_terminal_type(arg); - switch(etype) { - case ASN_BASIC_BIT_STRING: - svalue = _max?basic_max/8:0; - break; - case ASN_STRING_UTF8String: - svalue = _max?basic_max/6:0; - break; - case ASN_STRING_UniversalString: - svalue = _max?basic_max/4:0; - break; - case ASN_STRING_BMPString: - svalue = _max?basic_max/2:0; - break; - case ASN_BASIC_OCTET_STRING: - svalue = _max?basic_max:0; - break; - default: - if((etype & ASN_STRING_MASK)) { - svalue = _max?basic_max:0; - break; - } - svalue = _max?basic_max:basic_min; - break; - } - - return svalue; -} - -static asn1p_expr_type_e -_find_terminal_type(arg_t *arg) { - asn1p_expr_t *expr; - expr = asn1f_find_terminal_type_ex(arg->asn, arg->mod, arg->expr, NULL); - if(expr) return expr->expr_type; - return A1TC_INVALID; -} - diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c new file mode 100644 index 00000000..dd54224d --- /dev/null +++ b/libasn1compiler/asn1c_constraint.c @@ -0,0 +1,482 @@ +#include "asn1c_internal.h" +#include "asn1c_constraint.h" + +#include /* constraint groker from libasn1fix */ +#include /* other exportable stuff from libasn1fix */ + +static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range); +static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype); +static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype); +static asn1p_expr_type_e _find_terminal_type(arg_t *arg); +static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop); + +#define MKID(id) asn1c_make_identifier(0, (id), 0) + +static int global_compile_mark; + +int +asn1c_emit_constraint_checking_code(arg_t *arg) { + asn1cnst_range_t *r_size; + asn1cnst_range_t *r_value; + asn1p_expr_t *expr = arg->expr; + asn1p_expr_type_e etype; + asn1p_constraint_t *ct; + int got_something = 0; + + ct = expr->combined_constraints; + if(ct == NULL) + return 1; /* No additional constraints defined */ + + etype = _find_terminal_type(arg); + + r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE, 0, 0); + r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0, 0); + if(r_value) { + if(r_value->not_PER_visible + || r_value->extensible + || r_value->empty_constraint + || (r_value->left.type == ARE_MIN + && r_value->right.type == ARE_MAX) + || (etype == ASN_BASIC_BOOLEAN + && r_value->left.value == 0 + && r_value->right.value == 1) + ) { + asn1constraint_range_free(r_value); + r_value = 0; + } + } + if(r_size) { + if(r_size->not_PER_visible + || r_size->extensible + || r_size->empty_constraint + || (r_size->left.value == 0 /* or .type == MIN */ + && r_size->right.type == ARE_MAX) + ) { + asn1constraint_range_free(r_size); + r_size = 0; + } + } + + OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier)); + + if(r_size || r_value) { + if(r_size) { + OUT("size_t size;\n"); + } + if(r_value) + switch(etype) { + case ASN_BASIC_INTEGER: + case ASN_BASIC_ENUMERATED: + OUT("long value;\n"); + break; + case ASN_BASIC_BOOLEAN: + OUT("int value;\n"); + break; + default: + break; + } + } + + OUT("\n"); + + /* + * Protection against null input. + */ + OUT("if(!sptr) {\n"); + INDENT(+1); + OUT("_ASN_ERRLOG(app_errlog, app_key,\n"); + OUT("\t\"%%s: value not given\", td->name);\n"); + OUT("return -1;\n"); + INDENT(-1); + OUT("}\n"); + OUT("\n"); + + if(r_value) + emit_value_determination_code(arg, etype); + if(r_size) + emit_size_determination_code(arg, etype); + + /* + * Here is an if() {} else {} constaint checking code. + */ + OUT("\n"); + OUT("if("); + INDENT(+1); + if(r_size) { + if(got_something++) { OUT("\n"); OUT(" && "); } + OUT("("); + emit_range_comparison_code(arg, r_size, "size", 0, -1); + OUT(")"); + } + if(r_value) { + if(got_something++) { OUT("\n"); OUT(" && "); } + OUT("("); + if(etype == ASN_BASIC_BOOLEAN) + emit_range_comparison_code(arg, r_value, + "value", 0, 1); + else + emit_range_comparison_code(arg, r_value, + "value", -1, -1); + OUT(")"); + } + if(ct->_compile_mark) { + if(got_something++) { OUT("\n"); OUT(" && "); } + OUT("check_permitted_alphabet_%d(sptr)", + ct->_compile_mark); + } + if(!got_something) { + OUT("1 /* No applicable constraints whatsoever */"); + } + INDENT(-1); + OUT(") {\n"); + INDENT(+1); + OUT("/* Constraint check succeeded */\n"); + OUT("return 1;\n"); + INDENT(-1); + OUT("} else {\n"); + INDENT(+1); + OUT("_ASN_ERRLOG(app_errlog, app_key,\n"); + OUT("\t\"%%s: constraint failed\", td->name);\n"); + OUT("return -1;\n"); + INDENT(-1); + OUT("}\n"); + + return 0; +} + +int +asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct) { + asn1_integer_t range_start; + asn1_integer_t range_stop; + asn1p_expr_type_e etype; + asn1cnst_range_t *range; + int table[256]; + int use_table; + + if(!ct) ct = arg->expr->combined_constraints; + if(!ct) return 0; + + etype = _find_terminal_type(arg); + + range = asn1constraint_compute_PER_range(etype, ct, ACT_CT_FROM, 0, 0); + if(!range) return 0; + + if(range->not_PER_visible + || range->extensible + || range->empty_constraint) { + asn1constraint_range_free(range); + return 0; + } + + range_start = range->left.value; + range_stop = range->right.value; + assert(range->left.type == ARE_VALUE); + assert(range->right.type == ARE_VALUE); + assert(range_start <= range_stop); + + range_start = 0; /* Force old behavior */ + + /* + * Check if we need a test table to check the alphabet. + */ + use_table = 1; + if((range_stop - range_start) > 255) + use_table = 0; + if(range->el_count == 0) + use_table = 0; + + if(!ct->_compile_mark) + ct->_compile_mark = ++global_compile_mark; + + if(use_table) { + int i, n = 0; + int untl; + memset(table, 0, sizeof(table)); + for(i = -1; i < range->el_count; i++) { + asn1cnst_range_t *r; + asn1_integer_t v; + if(i == -1) { + if(range->el_count) continue; + r = range; + } else { + r = range->elements[i]; + } + for(v = r->left.value; v <= r->right.value; v++) { + assert((v - range_start) >= 0); + assert((v - range_start) < 256); + table[v - range_start] = ++n; + } + } + + OUT("static int permitted_alphabet_table_%d[256] = {\n", + ct->_compile_mark); + untl = (range_stop - range_start) + 1; + untl += (untl % 16)?16 - (untl % 16):0; + for(n = 0; n < untl; n++) { + OUT("%d,", table[n]?1:0); + if(!((n+1) % 16)) { + int c; + if(!n) { + OUT("\n"); + continue; + } + OUT("\t/* "); + for(c = n - 15; c <= n; c++) { + if(table[c]) { + int a = c + range_start; + if(a > 0x20 && a < 0x80) + OUT("%c", a); + else + OUT("."); + } else { + OUT(" "); + } + } + OUT(" */"); + OUT("\n"); + } + } + OUT("};\n"); + OUT("\n"); + } + + OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n", + ct->_compile_mark); + INDENT(+1); + if(use_table) { + OUT("int *table = permitted_alphabet_table_%d;\n", + ct->_compile_mark); + emit_alphabet_check_loop(arg, 0); + } else { + emit_alphabet_check_loop(arg, range); + } + OUT("return 1;\n"); + INDENT(-1); + OUT("}\n"); + OUT("\n"); + + asn1constraint_range_free(range); + + return 0; +} + +static int +emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range) { + asn1p_expr_type_e etype; + asn1_integer_t natural_stop; + + etype = _find_terminal_type(arg); + + OUT("/* The underlying type is %s */\n", + ASN_EXPR_TYPE2STR(etype)); + OUT("const %s_t *st = sptr;\n", MKID(arg->expr->Identifier)); + + switch(etype) { + case ASN_STRING_UTF8String: + OUT("uint8_t *ch = st->buf;\n"); + OUT("uint8_t *end = ch + st->size;\n"); + OUT("\n"); + OUT("for(; ch < end; ch++) {\n"); + INDENT(+1); + OUT("uint8_t cv = *ch;\n"); + if(!range) OUT("if(cv >= 0x80) return 0;\n"); + natural_stop = 0xffffffffUL; + break; + case ASN_STRING_UniversalString: + OUT("uint32_t *ch = st->buf;\n"); + OUT("uint32_t *end = ch + st->size;\n"); + OUT("\n"); + OUT("if(st->size % 4) return 0; /* (size%4)! */\n"); + OUT("for(; ch < end; ch++) {\n"); + INDENT(+1); + OUT("uint32_t cv = (((uint8_t *)ch)[0] << 24)\n"); + OUT("\t\t| (((uint8_t *)ch)[1] << 16)\n"); + OUT("\t\t| (((uint8_t *)ch)[2] << 8)\n"); + OUT("\t\t| ((uint8_t *)ch)[3]\n"); + if(!range) OUT("if(cv > 255) return 0;\n"); + natural_stop = 0xffffffffUL; + break; + case ASN_STRING_BMPString: + OUT("uint16_t *ch = st->buf;\n"); + OUT("uint16_t *end = ch + st->size;\n"); + OUT("\n"); + OUT("if(st->size % 2) return 0; /* (size%2)! */\n"); + OUT("for(; ch < end; ch++) {\n"); + INDENT(+1); + OUT("uint16_t cv = (((uint8_t *)ch)[0] << 8)\n"); + OUT("\t\t| ((uint8_t *)ch)[1];\n"); + if(!range) OUT("if(cv > 255) return 0;\n"); + natural_stop = 0xffff; + break; + case ASN_BASIC_OCTET_STRING: + default: + OUT("uint8_t *ch = st->buf;\n"); + OUT("uint8_t *end = ch + st->size;\n"); + OUT("\n"); + OUT("for(; ch < end; ch++) {\n"); + INDENT(+1); + OUT("uint8_t cv = *ch;\n"); + natural_stop = 0xff; + break; + } + + if(range) { + OUT("if(!("); + emit_range_comparison_code(arg, range, "cv", 0, natural_stop); + OUT(")) return 0;\n"); + } else { + OUT("if(!table[cv]) return 0;\n"); + } + + INDENT(-1); + OUT("}\n"); + + return 0; +} + +static int +emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1_integer_t natural_start, asn1_integer_t natural_stop) { + int ignore_left; + int ignore_right; + int i; + + for(i = -1; i < range->el_count; i++) { + asn1cnst_range_t *r; + if(i == -1) { + if(range->el_count) continue; + r = range; + } else { + if(i) OUT(" || "); + r = range->elements[i]; + } + + if(r != range) OUT("("); + + ignore_left = (r->left.type == ARE_MIN) + || (natural_start != -1 + && r->left.value <= natural_start); + ignore_right = (r->right.type == ARE_MAX) + || (natural_stop != -1 + && r->right.value >= natural_stop); + if(ignore_left && ignore_right) { + OUT("1 /* Constraint matches natural range of %s */", + varname); + continue; + } + + if(ignore_left) { + OUT("%s <= %lld", varname, + (long long)r->right.value); + } else if(ignore_right) { + OUT("%s >= %lld", varname, + (long long)r->left.value); + } else if(r->left.value == r->right.value) { + OUT("%s == %lld", varname, + (long long)r->right.value); + } else { + OUT("%s >= %lld && %s <= %lld", + varname, + (long long)r->left.value, + varname, + (long long)r->right.value); + } + if(r != range) OUT(")"); + } + + return 0; +} + +static int +emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype) { + + switch(etype) { + case ASN_BASIC_BIT_STRING: + OUT("if(st->size > 0) {\n"); + OUT("\t/* Size in bits */\n"); + OUT("\tsize = (st->size - 1) - (st->buf[0] & 0x7);\n"); + OUT("} else {\n"); + OUT("\tsize = 0;\n"); + OUT("}\n"); + break; + case ASN_STRING_UniversalString: + OUT("size = st->size >> 2;\t/* 4 byte per character */\n"); + break; + case ASN_STRING_BMPString: + OUT("size = st->size >> 1;\t/* 2 byte per character */\n"); + break; + case ASN_STRING_UTF8String: + OUT("size = UTF8String_length(st, td->name, app_errlog, app_key);\n"); + OUT("if(size == (size_t)-1) return -1;\n"); + break; + case ASN_CONSTR_SET_OF: + case ASN_CONSTR_SEQUENCE_OF: + OUT("{ /* Determine the number of elements */\n"); + INDENT(+1); + OUT("A_%s_OF(void) *list;\n", + etype==ASN_CONSTR_SET_OF?"SET":"SEQUENCE"); + OUT("(void *)list = st;\n"); + OUT("size = list->count;\n"); + INDENT(-1); + OUT("}\n"); + break; + default: + if((etype & ASN_STRING_MASK) + || etype == ASN_BASIC_OCTET_STRING) { + OUT("size = st->size;\n"); + break; + } else { + const char *type_name = ASN_EXPR_TYPE2STR(etype); + if(!type_name) type_name = arg->expr->Identifier; + WARNING("SizeConstraint is not defined for %s", + type_name); + OUT_NOINDENT("#warning SizeConstraint " + "is not defined for %s!\n", type_name); + OUT("size = st->size;\n"); + } + return -1; + } + + return 0; +} + +static int +emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype) { + + switch(etype) { + case ASN_BASIC_INTEGER: + case ASN_BASIC_ENUMERATED: + if(arg->flags & A1C_USE_NATIVE_INTEGERS) { + OUT("value = *(int *)st;\n"); + } else { + OUT("if(asn1_INTEGER2long(st, &value)) {\n"); + INDENT(+1); + OUT("_ASN_ERRLOG(app_errlog, app_key,\n"); + OUT("\t\"%%s: value too large\", td->name);\n"); + OUT("return -1;\n"); + INDENT(-1); + OUT("}\n"); + } + break; + case ASN_BASIC_BOOLEAN: + OUT("value = (*(int *)st) ? 1 : 0;\n"); + break; + default: + WARNING("Value cannot be determined " + "for constraint check for %s at line %d\n", + arg->expr->Identifier, arg->expr->_lineno); + OUT("#error Value cannot be determined for %s at %d\n", + arg->expr->Identifier, arg->expr->_lineno); + break; + } + + return 0; +} + +static asn1p_expr_type_e +_find_terminal_type(arg_t *arg) { + asn1p_expr_t *expr; + expr = asn1f_find_terminal_type_ex(arg->asn, arg->mod, arg->expr, NULL); + if(expr) return expr->expr_type; + return A1TC_INVALID; +} + diff --git a/libasn1compiler/asn1c_constraint.h b/libasn1compiler/asn1c_constraint.h new file mode 100644 index 00000000..481c0b34 --- /dev/null +++ b/libasn1compiler/asn1c_constraint.h @@ -0,0 +1,7 @@ +#ifndef _ASN1C_CONSTRAINT_H_ +#define _ASN1C_CONSTRAINT_H_ + +int asn1c_emit_constraint_tables(arg_t *arg, asn1p_constraint_t *ct); +int asn1c_emit_constraint_checking_code(arg_t *arg); + +#endif /* _ASN1C_CONSTRAINT_H_ */ diff --git a/libasn1compiler/asn1c_internal.h b/libasn1compiler/asn1c_internal.h index 08a490fb..061b9363 100644 --- a/libasn1compiler/asn1c_internal.h +++ b/libasn1compiler/asn1c_internal.h @@ -11,7 +11,7 @@ #include /* for unlink(2) */ #include /* for open(2) */ #include /* for glob(3) */ -#include +#include /* for strlen(3) and memset(3) */ #include /* for isalnum(3) */ #include #include