static void asn1constraint_range_free_outer(asn1cnst_range_t *cr) { if(cr) { int i; if(cr->elements) { for(i = 0; i < cr->el_count; i++) asn1constraint_range_free(cr->elements[i]); free(cr->elements); } memset(cr, 0, sizeof(*cr)); } }
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; int alphabet_table_compiled; int produce_st = 0; int ulong_optimize = 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,0); r_size =asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE, 0,0,0); if(r_value) { if(r_value->incompatible || 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->incompatible || 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; } } /* * Do we really need an "*st = sptr" pointer? */ switch(etype) { case ASN_BASIC_INTEGER: case ASN_BASIC_ENUMERATED: if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT) produce_st = 1; break; case ASN_BASIC_REAL: if(!(arg->flags & A1C_USE_NATIVE_TYPES)) produce_st = 1; break; case ASN_BASIC_BIT_STRING: case ASN_BASIC_OCTET_STRING: produce_st = 1; break; default: if(etype & ASN_STRING_MASK) produce_st = 1; break; } if(produce_st) { char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE); OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname); } 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: if(native_long_sign(r_value) >= 0) { ulong_optimize = ulong_optimization(etype, r_size, r_value); if(!ulong_optimize) { OUT("unsigned long value;\n"); } } else { OUT("long value;\n"); } break; case ASN_BASIC_REAL: OUT("double value;\n"); break; case ASN_BASIC_BOOLEAN: OUT("BOOLEAN_t value;\n"); break; default: break; } } OUT("\n"); /* * Protection against null input. */ OUT("if(!sptr) {\n"); INDENT(+1); OUT("_ASN_CTFAIL(app_key, td, sptr,\n"); OUT("\t\"%%s: value not given (%%s:%%d)\",\n"); OUT("\ttd->name, __FILE__, __LINE__);\n"); OUT("return -1;\n"); INDENT(-1); OUT("}\n"); OUT("\n"); if((r_value) && (!ulong_optimize)) emit_value_determination_code(arg, etype, r_value); if(r_size) emit_size_determination_code(arg, etype); INDENT(-1); REDIR(OT_CTABLES); /* Emit FROM() tables */ alphabet_table_compiled = (asn1c_emit_constraint_tables(arg, r_size?1:0) == 1); REDIR(OT_CODE); INDENT(+1); /* * Optimization for unsigned longs. */ if(ulong_optimize) { OUT("\n"); OUT("/* Constraint check succeeded */\n"); OUT("return 0;\n"); return 0; } /* * Here is an if() {} else {} consrtaint 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(alphabet_table_compiled) { if(got_something++) { OUT("\n"); OUT(" && "); } OUT("!check_permitted_alphabet_%d(%s)", arg->expr->_type_unique_index, produce_st ? "st" : "sptr"); } if(!got_something) { OUT("1 /* No applicable constraints whatsoever */"); OUT(") {\n"); INDENT(-1); INDENTED(OUT("/* Nothing is here. See below */\n")); OUT("}\n"); OUT("\n"); return 1; } INDENT(-1); OUT(") {\n"); INDENT(+1); switch(etype) { case ASN_CONSTR_SEQUENCE_OF: case ASN_CONSTR_SET_OF: OUT("/* Perform validation of the inner elements */\n"); OUT("return td->check_constraints(td, sptr, ctfailcb, app_key);\n"); break; default: OUT("/* Constraint check succeeded */\n"); OUT("return 0;\n"); } INDENT(-1); OUT("} else {\n"); INDENT(+1); OUT("_ASN_CTFAIL(app_key, td, sptr,\n"); OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n"); OUT("\ttd->name, __FILE__, __LINE__);\n"); OUT("return -1;\n"); INDENT(-1); OUT("}\n"); return 0; }
static int asn1c_emit_constraint_tables(arg_t *arg, int got_size) { asn1c_integer_t range_start; asn1c_integer_t range_stop; asn1p_expr_type_e etype; asn1cnst_range_t *range; asn1p_constraint_t *ct; int utf8_full_alphabet_check = 0; int max_table_size = 256; int table[256]; int use_table; 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,0); if(!range) return 0; if(range->incompatible || range->empty_constraint) { asn1constraint_range_free(range); return 0; } if(range->left.type == ARE_MIN && range->right.type == ARE_MAX) { /* * The permitted alphabet constraint checker code guarantees * that either both bounds (left/right) are present, or * they're absent simultaneously. Thus, this assertion * legitimately holds true. */ assert(range->el_count == 0); /* The full range is specified. Ignore it. */ 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->el_count == 0) { /* * It's better to have a short if() check * than waste 1k of table space */ use_table = 0; } if((range_stop - range_start) > 255) use_table = 0; if(etype == ASN_STRING_UTF8String) { if(range_stop >= 0x80) use_table = 0; else max_table_size = 128; } if(use_table) { int cardinal = 0; int i, n = 0; int untl; memset(table, 0, sizeof(table)); for(i = -1; i < range->el_count; i++) { asn1cnst_range_t *r; asn1c_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) < max_table_size); table[v - range_start] = ++n; } } untl = (range_stop - range_start) + 1; untl += (untl % 16)?16 - (untl % 16):0; OUT("static int permitted_alphabet_table_%d[%d] = {\n", arg->expr->_type_unique_index, max_table_size); for(n = 0; n < untl; n++) { cardinal += table[n] ? 1 : 0; OUT("%2d,", table[n]); if(!((n+1) % 16)) { int c; if(!n || (n-15) + range_start >= 0x80) { 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"); if((arg->flags & A1C_GEN_PER) && (etype & ASN_STRING_KM_MASK)) { int c; OUT("static int permitted_alphabet_code2value_%d[%d] = {\n", arg->expr->_type_unique_index, cardinal); for(n = c = 0; c < max_table_size; c++) { if(table[c]) { OUT("%d,", c); if(!((++n) % 16)) OUT("\n"); } } OUT("};\n"); OUT("\n"); DEBUG("code2value map gen for %s", arg->expr->Identifier); arg->expr->_mark |= TM_PERFROMCT; } OUT("\n"); } else if(etype == ASN_STRING_UTF8String) { /* * UTF8String type is a special case in many respects. */ if(got_size) { /* * Size has been already determined. * The UTF8String length checker also checks * for the syntax validity, so we don't have * to repeat this process twice. */ asn1constraint_range_free(range); return 0; } else { utf8_full_alphabet_check = 1; } } else { /* * This permitted alphabet check will be * expressed using conditional statements * instead of table lookups. Table would be * to large or otherwise inappropriate (too sparse?). */ } OUT("static int check_permitted_alphabet_%d(const void *sptr) {\n", arg->expr->_type_unique_index); INDENT(+1); if(utf8_full_alphabet_check) { OUT("if(UTF8String_length((const UTF8String_t *)sptr) < 0)\n"); OUT("\treturn -1; /* Alphabet (sic!) test failed. */\n"); OUT("\n"); } else { if(use_table) { OUT("int *table = permitted_alphabet_table_%d;\n", arg->expr->_type_unique_index); emit_alphabet_check_loop(arg, 0); } else { emit_alphabet_check_loop(arg, range); } } OUT("return 0;\n"); INDENT(-1); OUT("}\n"); OUT("\n"); asn1constraint_range_free(range); return 1; }
static asn1cnst_range_t * asn1f_real_range_from_WCOMPS(const char *dbg_name, const asn1p_constraint_t *ct) { asn1cnst_range_t two = { {ARE_VALUE, 0, 2}, {ARE_VALUE, 0, 2}, 0, NULL, 0, 0, 0, 0, 0, 0, 0}; asn1cnst_range_t ten = { {ARE_VALUE, 0, 10}, {ARE_VALUE, 0, 10}, 0, NULL, 0, 0, 0, 0, 0, 0, 0}; asn1cnst_range_t *two_ten[] = {&two, &ten}; /* Interpretation of X.680 #21.5 */ asn1cnst_range_t mantissa_default_range = { {ARE_MIN, 0, 0}, {ARE_MAX, 0, 0}, 0, NULL, 0, 0, 0, 0, 0, 0, 0}; asn1cnst_range_t exponent_default_range = { {ARE_MIN, 0, 0}, {ARE_MAX, 0, 0}, 0, NULL, 0, 0, 0, 0, 0, 0, 0}; asn1cnst_range_t base_default_range = { {ARE_VALUE, 0, 2}, {ARE_MAX, 0, 10}, 0, two_ten, 2, 0, 0, 0, 0, 0, 0}; asn1cnst_range_t *mantissa = _range_clone(&mantissa_default_range); asn1cnst_range_t *exponent = _range_clone(&exponent_default_range); asn1cnst_range_t *base = _range_clone(&base_default_range); asn1cnst_range_t *range; #define FREE_MEB() \ do { \ _range_free(mantissa); \ _range_free(exponent); \ _range_free(base); \ } while(0) (void)dbg_name; assert(ct->type == ACT_CT_WCOMPS); range = _range_new(); range->incompatible = 1; for(unsigned i = 0; i < ct->el_count; i++) { struct asn1p_constraint_s *el = ct->elements[i]; asn1p_value_t *value = 0; asn1cnst_range_t **dst_range = 0; switch(el->type) { case ACT_EL_EXT: /* Some components might not be defined. */ assert(range->incompatible); FREE_MEB(); return range; default: assert(range->incompatible); FREE_MEB(); return range; case ACT_EL_VALUE: value = el->value; if(value->type != ATV_REFERENCED) { FREE_MEB(); return range; } break; } if(strcmp(asn1p_ref_string(value->value.reference), "mantissa") == 0) { dst_range = &mantissa; } else if(strcmp(asn1p_ref_string(value->value.reference), "exponent") == 0) { dst_range = &exponent; } else if(strcmp(asn1p_ref_string(value->value.reference), "base") == 0) { dst_range = &base; } else { FATAL("Invalid specification \"%s\" for REAL", asn1p_ref_string(value->value.reference)); FREE_MEB(); return range; } switch(el->el_count) { case 0: continue; case 1: break; default: FATAL("Too many constraints (%u) for \"%s\" for REAL", el->el_count, asn1p_ref_string(value->value.reference)); FREE_MEB(); return range; } asn1cnst_range_t *tmprange = asn1constraint_compute_constraint_range( dbg_name, ASN_BASIC_INTEGER, el->elements[0], ACT_EL_RANGE, *dst_range, 0, CPR_noflags); assert(tmprange); if(tmprange->incompatible) { _range_free(tmprange); FREE_MEB(); return range; } asn1constraint_range_free(*dst_range); *dst_range = tmprange; } range->incompatible = 0; /* X.696 #12.2 */ if(mantissa->left.type == ARE_VALUE && mantissa->right.type == ARE_VALUE && mantissa->left.value >= -16777215 && mantissa->right.value <= 16777215 && base->left.type == ARE_VALUE && base->right.type == ARE_VALUE && base->left.value == 2 && base->right.value == 2 && exponent->left.type == ARE_VALUE && exponent->right.type == ARE_VALUE && exponent->left.value >= -149 && exponent->right.value <= 104) { range->narrowing = NARROW_FLOAT32; } else /* X.696 #12.3 */ if(mantissa->left.type == ARE_VALUE && mantissa->right.type == ARE_VALUE && mantissa->left.value >= -9007199254740991ll && mantissa->right.value <= 9007199254740991ull && base->left.type == ARE_VALUE && base->right.type == ARE_VALUE && base->left.value == 2 && base->right.value == 2 && exponent->left.type == ARE_VALUE && exponent->right.type == ARE_VALUE && exponent->left.value >= -1074 && exponent->right.value <= 971) { range->narrowing = NARROW_DOUBLE64; } FREE_MEB(); return range; }