diff options
author | Bi-Ruei, Chiu <biruei.chiu@gmail.com> | 2017-05-07 21:00:51 +0800 |
---|---|---|
committer | Bi-Ruei, Chiu <biruei.chiu@gmail.com> | 2017-05-07 22:20:30 +0800 |
commit | 80fd3065f4868c5a9c6afe493391a45558ed8463 (patch) | |
tree | 9fc270cb66040f96a172437010156e88c3f566c7 /libasn1fix | |
parent | 4021e4ba623b2885a8c859379bc858644c2e1d34 (diff) |
Merge PR99 and its fixes to support parsing Information Object and Information Object Set
This is a collection of works :
1. Based on @zhanglei002's pull request 99.
2. A fix by @AuthenticEshkinKot and merged by @mouse07410 at
commit 2c8d366bbe1fc4e4c041e9b0eb9779f8a42d754b of https://github.com/mouse07410/asn1c
to support parsing of Information Object and Information Object Set
3. A fix by @Uri Blumenthal in asn1fix_derefv.c at :
commit ec0ade4f87c807e763e3f35fc5466adb6dda3473 of https://github.com/mouse07410/asn1c
to solve crash on asn1p_value_free().
4. My pull request 18 to @mouse07410's https://github.com/mouse07410/asn1c to solve
problems found during parsing ASN.1 modules of S1AP, RANAP and J2735-201603.
5. My pull request 22 to @mouse07410's https://github.com/mouse07410/asn1c to solve issue 147
and to solve the problem during parsing ASN.1 module of NBAP.
6. My pull request 23 to @mouse07410's https://github.com/mouse07410/asn1c to fix memory leakage
introduced in aforementioned commits.
Most code changes are the same as pull request 153 to this repository.
7. A fix of my bug in item 6 which result asn1c crash, fixed by @mouse07410.
Diffstat (limited to 'libasn1fix')
-rw-r--r-- | libasn1fix/asn1fix.c | 11 | ||||
-rw-r--r-- | libasn1fix/asn1fix_constraint.c | 26 | ||||
-rw-r--r-- | libasn1fix/asn1fix_cws.c | 216 | ||||
-rw-r--r-- | libasn1fix/asn1fix_cws.h | 1 | ||||
-rw-r--r-- | libasn1fix/asn1fix_derefv.c | 1 | ||||
-rw-r--r-- | libasn1fix/asn1fix_param.c | 22 | ||||
-rw-r--r-- | libasn1fix/asn1fix_retrieve.c | 66 | ||||
-rw-r--r-- | libasn1fix/asn1fix_value.c | 24 |
8 files changed, 289 insertions, 78 deletions
diff --git a/libasn1fix/asn1fix.c b/libasn1fix/asn1fix.c index 8d2317f4..e6af2f24 100644 --- a/libasn1fix/asn1fix.c +++ b/libasn1fix/asn1fix.c @@ -247,6 +247,7 @@ asn1f_fix_module__phase_2(arg_t *arg) { int ret; TQ_FOR(expr, &(arg->mod->members), next) { + arg->expr = expr; /* @@ -499,6 +500,16 @@ asn1f_check_duplicate(arg_t *arg) { arg->expr->Identifier)) continue; + /* resolve clash of Identifier in different modules */ + int oid_exist = (tmparg.expr->module->module_oid && arg->expr->module->module_oid); + if ((!oid_exist && strcmp(tmparg.expr->module->ModuleName, arg->expr->module->ModuleName)) || + (oid_exist && !asn1p_oid_compare(tmparg.expr->module->module_oid, arg->expr->module->module_oid))) { + + tmparg.expr->_mark |= TM_NAMECLASH; + arg->expr->_mark |= TM_NAMECLASH; + continue; + } + diff_files = strcmp(arg->mod->source_file_name, tmparg.mod->source_file_name) ? 1 : 0; diff --git a/libasn1fix/asn1fix_constraint.c b/libasn1fix/asn1fix_constraint.c index 847bdcea..97fa589b 100644 --- a/libasn1fix/asn1fix_constraint.c +++ b/libasn1fix/asn1fix_constraint.c @@ -4,6 +4,7 @@ static void _remove_extensions(arg_t *arg, asn1p_constraint_t *ct, int flast); static int constraint_type_resolve(arg_t *arg, asn1p_constraint_t *ct); +static int constraint_object_resolve(arg_t *arg, asn1p_value_t *value); static int constraint_value_resolve(arg_t *arg, asn1p_value_t **value, enum asn1p_constraint_type_e real_ctype); int @@ -214,6 +215,10 @@ asn1constraint_resolve(arg_t *arg, asn1p_constraint_t *ct, asn1p_expr_type_e ety &ct->range_stop, real_constraint_type); RET2RVAL(ret, rvalue); } + if (ct->value && ct->value->type == ATV_UNPARSED && etype == A1TC_CLASSDEF) { + ret = constraint_object_resolve(arg, ct->value); + RET2RVAL(ret, rvalue); + } /* * Proceed recursively. @@ -346,3 +351,24 @@ constraint_value_resolve(arg_t *arg, return rvalue; } +static int +constraint_object_resolve(arg_t *arg, asn1p_value_t *value) { + asn1p_expr_t tmp_expr = *arg->expr; + asn1p_expr_t *saved_expr = arg->expr; + + tmp_expr.meta_type = AMT_VALUE; + tmp_expr.expr_type = A1TC_REFERENCE; + tmp_expr.value = value; + arg->expr = &tmp_expr; + + if (asn1f_check_class_object(arg)) { + arg->expr = saved_expr; + FATAL("Parsing ObjectSet %s failed at %d", arg->expr->Identifier, + arg->expr->_lineno); + return -1; + } + + arg->expr = saved_expr; + return 0; +} + diff --git a/libasn1fix/asn1fix_cws.c b/libasn1fix/asn1fix_cws.c index 312a65b0..245b1c1b 100644 --- a/libasn1fix/asn1fix_cws.c +++ b/libasn1fix/asn1fix_cws.c @@ -6,6 +6,48 @@ static int _asn1f_parse_class_object_data(arg_t *, asn1p_expr_t *eclass, uint8_t *buf, const uint8_t *bend, int optional_mode, uint8_t **newpos); static int _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell, uint8_t *buf, const uint8_t *bend); +static asn1p_wsyntx_chunk_t *asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, uint8_t *buf); + +int +asn1f_check_class_object(arg_t *arg) { + asn1p_expr_t *expr = arg->expr; + asn1p_expr_t *eclass; + asn1p_ioc_row_t *row; + int ret; + + if(expr->meta_type != AMT_VALUE + || expr->expr_type != A1TC_REFERENCE + || !expr->value + || expr->value->type != ATV_UNPARSED) + return 0; + + eclass = asn1f_find_terminal_type(arg, expr); + if(!eclass + || eclass->meta_type != AMT_OBJECTCLASS + || eclass->expr_type != A1TC_CLASSDEF) { + return 0; + } + + if(!eclass->with_syntax) { + DEBUG("Can't process classes without %s just yet", + "WITH SYNTAX"); + return 0; + } + + row = asn1p_ioc_row_new(eclass); + assert(row); + + ret = _asn1f_parse_class_object_data(arg, eclass, row, + eclass->with_syntax, + expr->value->value.string.buf + 1, + expr->value->value.string.buf + + expr->value->value.string.size - 1, + 0, 0); + + asn1p_ioc_row_delete(row); + + return ret; +} int asn1f_parse_class_object(arg_t *arg) { @@ -102,32 +144,25 @@ _asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass, case WC_WHITESPACE: break; /* Ignore whitespace */ case WC_FIELD: { struct asn1p_ioc_cell_s *cell; - int lbraces = 0; - uint8_t *p; + asn1p_wsyntx_chunk_t *next_literal; + uint8_t *buf_old = buf; + uint8_t *p = 0; SKIPSPACES; - p = buf; - if(p < bend && *p == '{') - lbraces = 1, p++; - for(; p < bend; p++) { - if(lbraces) { - /* Search the terminating brace */ - switch(*p) { - case '}': lbraces--; break; - case '{': lbraces++; break; - } - } else if(isspace(*p)) { - break; + next_literal = asn1f_next_literal_chunk(syntax, chunk, buf); + if(!next_literal) { + p += (bend - p); + } else { + p = (uint8_t *)strstr((char *)buf, (char *)next_literal->content.token); + if(!p) { + if (!optional_mode) + FATAL("Next literal \"%s\" not found !", next_literal->content.token); + + if(newpos) *newpos = buf_old; + return -1; } } - if(lbraces) { - FATAL("Field reference %s found in class value definition for %s at line %d can not be satisfied by broken value \"%s\"", - chunk->content.token, - arg->expr->Identifier, arg->expr->_lineno, buf); - if(newpos) *newpos = buf; - return -1; - } cell = asn1p_ioc_row_cell_fetch(row, chunk->content.token); if(cell == NULL) { @@ -167,10 +202,15 @@ _asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass, static int _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell, uint8_t *buf, const uint8_t *bend) { - asn1p_expr_t *expr; - asn1p_ref_t *ref; + asn1p_expr_t *expr = (asn1p_expr_t *)NULL; int idLength; char *p; + int new_ref = 1; + asn1p_t *asn; + asn1p_module_t *mod; + asn1p_expr_t *type_expr = (asn1p_expr_t *)NULL; + int i, ret = 0, psize; + char *pp; if((bend - buf) <= 0) { FATAL("Assignment warning: empty string is being assigned into %s for %s at line %d", @@ -183,37 +223,89 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_i assert(p); memcpy(p, buf, bend - buf); p[bend - buf] = '\0'; + /* remove trailing space */ + for (i = bend - buf - 1; (i > 0) && isspace(p[i]); i--) + p[i] = '\0'; - if(!isalpha(*p)) { + /* This value 100 should be larger than following formatting string */ + psize = bend - buf + 100; + pp = malloc(psize); + if(pp == NULL) { + free(p); + return -1; + } - if(isdigit(*p)) { - asn1c_integer_t value; - if(asn1p_atoi(p, &value)) { - FATAL("Value %s at line %d is too large for this compiler! Contact the asn1c author.\n", p, arg->expr->_lineno); - return -1; - } - expr = asn1p_expr_new(arg->expr->_lineno, arg->expr->module); - expr->Identifier = p; - expr->meta_type = AMT_VALUE; - expr->expr_type = ASN_BASIC_INTEGER; - expr->value = asn1p_value_fromint(value); + if(cell->field->expr_type == A1TC_CLASSFIELD_TFS) { + ret = snprintf(pp, psize, + "M DEFINITIONS ::=\nBEGIN\n" + "V ::= %s\n" + "END\n", + p + ); + } else if(cell->field->expr_type == A1TC_CLASSFIELD_FTVFS) { + type_expr = TQ_FIRST(&(cell->field->members)); + ret = snprintf(pp, psize, + "M DEFINITIONS ::=\nBEGIN\n" + "v %s ::= %s\n" + "END\n", + type_expr->reference ? + type_expr->reference->components[0].name : + _asn1p_expr_type2string(type_expr->expr_type), + p + ); + } else { + WARNING("asn1c only be able to parse TypeFieldSpec and FixedTypeValueFieldSpec. Failed when parsing %s at line %d\n", p, arg->expr->_lineno); + free(p); /* bad idea freeing object you refer to later! */ + free(pp); + return -1; + } + DEBUG("ASN.1 :\n\n%s\n", pp); + + assert(ret < psize); + psize = ret; + + asn = asn1p_parse_buffer(pp, psize, A1P_NOFLAGS); + free(pp); + if(asn == NULL) { + FATAL("Cannot parse Setting token %s " + "at line %d", + p, + arg->expr->_lineno + ); + free(p); + return -1; + } else { + mod = TQ_FIRST(&(asn->modules)); + assert(mod); + expr = TQ_REMOVE(&(mod->members), next); + assert(expr); + + free(expr->Identifier); + expr->module = arg->expr->module; + expr->_lineno = arg->expr->_lineno; + if (expr->reference) { + expr->reference->module = arg->expr->module; + expr->reference->_lineno = arg->expr->_lineno; + expr->Identifier = strdup(expr->reference->components[expr->reference->comp_count - 1].name); } else { - WARNING("asn1c is not yet able to parse arbitrary direct values; try converting %s at line %d to a reference.", p, arg->expr->_lineno); - free(p); - return 1; + expr->Identifier = p; } - } else { - ref = asn1p_ref_new(arg->expr->_lineno); - asn1p_ref_add_component(ref, p, RLT_UNKNOWN); - assert(ref); + asn1p_delete(asn); + } + + if(expr->reference && + !asn1f_lookup_symbol(arg, arg->mod, expr->rhs_pspecs, expr->reference)) { - expr = asn1f_lookup_symbol(arg, arg->mod, arg->expr->rhs_pspecs, ref); - if(!expr) { + asn1p_ref_free(expr->reference); + new_ref = 0; + expr->reference = type_expr->reference; + if (asn1f_value_resolve(arg, expr, 0)) { + expr->reference = 0; + asn1p_expr_free(expr); FATAL("Cannot find %s referenced by %s at line %d", p, arg->expr->Identifier, arg->expr->_lineno); - asn1p_ref_free(ref); - free(p); + free(p); /* freeing must happen *after* p was used in FATAL() */ return -1; } } @@ -222,11 +314,43 @@ _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_i cell->field->Identifier, p, expr->Identifier); cell->value = expr; + cell->new_ref = new_ref; idLength = strlen(expr->Identifier); if(row->max_identifier_length < idLength) row->max_identifier_length = idLength; + if(expr->Identifier != p) + free(p); + return 0; } +static asn1p_wsyntx_chunk_t * +asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, uint8_t *buf) +{ + asn1p_wsyntx_chunk_t *next_chunk; + + next_chunk = TQ_NEXT(chunk, next); + do { + if(next_chunk == (struct asn1p_wsyntx_chunk_s *)0) { + if(!syntax->parent) + break; + next_chunk = TQ_NEXT(syntax->parent, next); + } else if(next_chunk->type == WC_LITERAL) { + if(strstr((char *)buf, (char *)next_chunk->content.token)) + break; + if(!syntax->parent) + break; + next_chunk = TQ_NEXT(syntax->parent, next); + } else if(next_chunk->type == WC_WHITESPACE) { + next_chunk = TQ_NEXT(next_chunk, next); + } else if(next_chunk->type == WC_OPTIONALGROUP) { + syntax = next_chunk->content.syntax; + next_chunk = TQ_FIRST(((&next_chunk->content.syntax->chunks))); + } else + break; + } while (next_chunk); + + return next_chunk; +} diff --git a/libasn1fix/asn1fix_cws.h b/libasn1fix/asn1fix_cws.h index 3d24f163..e998a28a 100644 --- a/libasn1fix/asn1fix_cws.h +++ b/libasn1fix/asn1fix_cws.h @@ -4,6 +4,7 @@ /* * Parse class objects */ +int asn1f_check_class_object(arg_t *arg); int asn1f_parse_class_object(arg_t *arg); #endif /* ASN1FIX_CLASS_WITH_SYNTAX_H */ diff --git a/libasn1fix/asn1fix_derefv.c b/libasn1fix/asn1fix_derefv.c index 5436d58b..3942d16c 100644 --- a/libasn1fix/asn1fix_derefv.c +++ b/libasn1fix/asn1fix_derefv.c @@ -48,6 +48,7 @@ asn1f_fix_dereference_defaults(arg_t *arg) { child->marker.default_value=expr->marker.default_value; ret = asn1f_fix_dereference_defaults(&tmparg); expr->marker.default_value = child->marker.default_value; + child->marker.default_value = 0; /* ULB: trying to ensure there isn't another pointer to the same value object */ if(ret == 0) return 0; /* Finished */ } diff --git a/libasn1fix/asn1fix_param.c b/libasn1fix/asn1fix_param.c index f8e3a2e7..fe98081a 100644 --- a/libasn1fix/asn1fix_param.c +++ b/libasn1fix/asn1fix_param.c @@ -18,6 +18,7 @@ asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_ps resolver_arg_t rarg; /* resolver argument */ asn1p_expr_t *exc; /* expr clone */ asn1p_expr_t *rpc; /* rhs_pspecs clone */ + asn1p_expr_t *m; /* expr members */ void *p; struct asn1p_pspec_s *pspec; int npspecs; @@ -69,6 +70,17 @@ asn1f_parameterization_fork(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *rhs_ps pspec->my_clone = exc; exc->spec_index = npspecs; + /* Passing arguments to members and type references */ + exc->rhs_pspecs = expr->rhs_pspecs ? expr->rhs_pspecs : rhs_pspecs; + if(exc->rhs_pspecs) + exc->rhs_pspecs->ref_cnt++; + + TQ_FOR(m, &exc->members, next) { + m->rhs_pspecs = exc->rhs_pspecs; + if (exc->rhs_pspecs) + exc->rhs_pspecs->ref_cnt++; + } + DEBUG("Forked new parameterization for %s", expr->Identifier); /* Commit */ @@ -86,7 +98,15 @@ compare_specializations(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) { if(ac == bc) continue; if(ac->meta_type != bc->meta_type) break; if(ac->expr_type != bc->expr_type) break; - + /* Maybe different object sets */ + if(ac->constraints && bc->constraints + && ac->constraints->containedSubtype + && bc->constraints->containedSubtype + && ac->constraints->containedSubtype->type == ATV_REFERENCED + && bc->constraints->containedSubtype->type == ATV_REFERENCED + && strcmp(ac->constraints->containedSubtype->value.reference->components[0].name, + bc->constraints->containedSubtype->value.reference->components[0].name)) + break; if(!ac->reference && !bc->reference) continue; diff --git a/libasn1fix/asn1fix_retrieve.c b/libasn1fix/asn1fix_retrieve.c index 52506b81..86540b94 100644 --- a/libasn1fix/asn1fix_retrieve.c +++ b/libasn1fix/asn1fix_retrieve.c @@ -287,14 +287,13 @@ asn1f_lookup_symbol_impl(arg_t *arg, asn1p_module_t *mod, asn1p_expr_t *rhs_pspe break; } if(ref_tc) { + /* It is acceptable that we don't use input parameters */ if(rhs_pspecs && !ref_tc->lhs_params) { - FATAL("Parameterized type %s expected " + WARNING("Parameterized type %s expected " "for %s at line %d", ref_tc->Identifier, asn1f_printable_reference(ref), ref->_lineno); - errno = EPERM; - return NULL; } if(!rhs_pspecs && ref_tc->lhs_params) { FATAL("Type %s expects specialization " @@ -320,30 +319,33 @@ asn1f_lookup_symbol_impl(arg_t *arg, asn1p_module_t *mod, asn1p_expr_t *rhs_pspe */ { /* Search inside standard module */ - static asn1p_oid_t *uioc_oid; - if(!uioc_oid) { - asn1p_oid_arc_t arcs[] = { - { 1, "iso" }, - { 3, "org" }, - { 6, "dod" }, - { 1, "internet" }, - { 4, "private" }, - { 1, "enterprise" }, - { 9363, "spelio" }, - { 1, "software" }, - { 5, "asn1c" }, - { 3, "standard-modules" }, - { 0, "auto-imported" }, - { 1, 0 } - }; + asn1p_oid_t *uioc_oid; + asn1p_oid_arc_t arcs[] = { + { 1, "iso" }, + { 3, "org" }, + { 6, "dod" }, + { 1, "internet" }, + { 4, "private" }, + { 1, "enterprise" }, + { 9363, "spelio" }, + { 1, "software" }, + { 5, "asn1c" }, + { 3, "standard-modules" }, + { 0, "auto-imported" }, + { 1, 0 } + }; + + if(!imports_from) { uioc_oid = asn1p_oid_construct(arcs, sizeof(arcs)/sizeof(arcs[0])); - } - if(!imports_from && (!mod->module_oid - || asn1p_oid_compare(mod->module_oid, uioc_oid))) { - imports_from = asn1f_lookup_module(arg, - "ASN1C-UsefulInformationObjectClasses", - uioc_oid); + + if(!mod->module_oid + || asn1p_oid_compare(mod->module_oid, uioc_oid)) + imports_from = asn1f_lookup_module(arg, + "ASN1C-UsefulInformationObjectClasses", + uioc_oid); + + asn1p_oid_free(uioc_oid); if(imports_from) goto importing; } } @@ -430,10 +432,16 @@ asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, enum ftt_what what) { */ tc = asn1f_lookup_symbol(arg, expr->module, expr->rhs_pspecs, ref); if(tc == NULL) { - DEBUG("\tSymbol \"%s\" not found: %s", - asn1f_printable_reference(ref), - strerror(errno)); - return NULL; + /* + * Lookup inside the ref's module and its IMPORTS section. + */ + tc = asn1f_lookup_symbol(arg, ref->module, expr->rhs_pspecs, ref); + if(tc == NULL) { + DEBUG("\tSymbol \"%s\" not found: %s", + asn1f_printable_reference(ref), + strerror(errno)); + return NULL; + } } /* diff --git a/libasn1fix/asn1fix_value.c b/libasn1fix/asn1fix_value.c index 0e60ef7b..b881afca 100644 --- a/libasn1fix/asn1fix_value.c +++ b/libasn1fix/asn1fix_value.c @@ -199,8 +199,28 @@ asn1f_look_value_in_type(arg_t *arg, : "<not found>" ); - if(child_expr && child_expr->value) { - if(_asn1f_copy_value(arg, value_expr, child_expr)) + if(child_expr) { + /* Maybe hasn't been fixed yet. */ + if (!child_expr->value) { + asn1p_expr_t *saved_expr = arg->expr; + arg->expr = type_expr; + switch (type_expr->expr_type) { + case ASN_BASIC_INTEGER: + asn1f_fix_integer(arg); + break; + case ASN_BASIC_ENUMERATED: + asn1f_fix_enum(arg); + break; + default: + WARNING("Unexpected type %s for %s", + type_expr->expr_type, + type_expr->Identifier); + return -1; + } + arg->expr = saved_expr; + } + if(child_expr->value && _asn1f_copy_value(arg, + value_expr, child_expr)) return -1; /* Fall through */ } |