NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1fix / asn1fix.c
1 #include "asn1fix_internal.h"
2 #include "asn1fix.h"
3
4 /* Print everything to stderr */
5 static void _default_error_logger(int _severity, const char *fmt, ...);
6
7 /*
8  * Internal check functions.
9  */
10 static int asn1f_fix_module__phase_1(arg_t *arg);
11 static int asn1f_fix_module__phase_2(arg_t *arg);
12 static int asn1f_fix_simple(arg_t *arg);        /* For INTEGER/ENUMERATED */
13 static int asn1f_fix_constructed(arg_t *arg);   /* For SEQUENCE/SET/CHOICE */
14 static int asn1f_resolve_constraints(arg_t *arg); /* For subtype constraints */
15 static int asn1f_check_constraints(arg_t *arg); /* For subtype constraints */
16 static int asn1f_check_duplicate(arg_t *arg);
17 static int asn1f_apply_unique_index(arg_t *arg);
18 static int phase_1_1(arg_t *arg, int prm2);
19
20 arg_t a1f_replace_me_with_proper_interface_arg;
21
22 /*
23  * Scan every module defined here in search for inconsistences.
24  */
25 int
26 asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
27                 error_logger_f error_logger) {
28         arg_t arg;
29         int fatals = 0;
30         int warnings = 0;
31         int ret;
32
33         /*
34          * Check validity of arguments.
35          */
36         if(asn == NULL) {
37                 errno = EINVAL;
38                 return -1;
39         }
40
41         /*
42          * If errors handler is not specified, default to internal one.
43          */
44         if(error_logger == 0) {
45                 error_logger = _default_error_logger;
46         }
47
48         memset(&arg, 0, sizeof(arg));
49         arg.asn = asn;
50         arg.eh = error_logger;
51
52         if(flags & A1F_DEBUG) {
53                 arg.debug = arg.eh;
54                 arg.debug(-1, "Called %s() with flags %d", __func__, flags);
55                 flags &= ~A1F_DEBUG;
56         }
57
58         /* Allow SIZE() constraint for INTEGER and other types */
59         if(flags & A1F_EXTENDED_SizeConstraint) {
60                 arg.flags |= A1F_EXTENDED_SizeConstraint;
61                 flags &= ~A1F_EXTENDED_SizeConstraint;
62                 if(arg.debug) {
63                         arg.debug(-1,
64                                 "Extended SizeConstraint support enabled");
65                 }
66         }
67
68         a1f_replace_me_with_proper_interface_arg = arg;
69
70         /*
71          * Check that we haven't missed an unknown flag.
72          */
73         if(flags) {
74                 errno = EINVAL;
75                 return -1;
76         }
77
78     /*
79      * Process each module in the list.
80      * PHASE I.
81      */
82     TQ_FOR(arg.mod, &(asn->modules), mod_next) {
83         arg.ns = asn1_namespace_new_from_module(arg.mod, 0);
84         ret = asn1f_fix_module__phase_1(&arg);
85         /*
86          * These lines are used for illustration purposes.
87          * RET2RVAL() is used everywhere else.
88          */
89         if(ret == -1) fatals++;
90         if(ret == 1) warnings++;
91         asn1_namespace_free(arg.ns);
92         arg.ns = 0;
93     }
94     /* PHASE II. */
95     TQ_FOR(arg.mod, &(asn->modules), mod_next) {
96         arg.ns = asn1_namespace_new_from_module(arg.mod, 0);
97         ret = asn1f_fix_module__phase_2(&arg);
98         if(ret == -1) fatals++;
99         if(ret == 1) warnings++;
100         asn1_namespace_free(arg.ns);
101         arg.ns = 0;
102     }
103
104     memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
105
106         /*
107          * Compute a return value.
108          */
109         return fatals?-1:warnings?1:0;
110 }
111
112 /*
113  * Check the internals of a single module.
114  */
115 static int
116 asn1f_fix_module__phase_1(arg_t *arg) {
117         asn1p_expr_t *expr;
118         int rvalue = 0;
119         int ret;
120         asn1p_module_t *omod;
121
122         /*
123          * Check that we don't have a similarly named module.
124          */
125         TQ_FOR(omod, &arg->asn->modules, mod_next) {
126                 int sameNames;
127                 if(omod == arg->mod) break;
128                 sameNames = strcmp(omod->ModuleName, arg->mod->ModuleName)?0:1;
129                 if(omod->module_oid && arg->mod->module_oid) {
130                         /* Compare only the OID. */
131                         if(asn1p_oid_compare(omod->module_oid,
132                                         arg->mod->module_oid) == 0) {
133                                 FATAL("ASN.1 module %s in %s "
134                                         "has the same OBJECT IDENTIFIER"
135                                         " as module %s",
136                                         omod->ModuleName,
137                                         omod->source_file_name,
138                                         arg->mod->ModuleName
139                                 );
140                                 RET2RVAL(-1, rvalue);
141                         } else if(sameNames) {
142                                 WARNING("ASN.1 module %s is defined more than once, with different OIDs", omod->ModuleName);
143                                 RET2RVAL(1, rvalue);
144                         }
145                 } else if(sameNames) {
146                         FATAL("ASN.1 module %s is defined more than once",
147                                 omod->ModuleName);
148                         RET2RVAL(-1, rvalue);
149                 }
150         }
151
152         switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
153         case MSF_NOFLAGS:
154         case MSF_EXPLICIT_TAGS:
155         case MSF_IMPLICIT_TAGS:
156         case MSF_AUTOMATIC_TAGS:
157                 break;
158         default:
159                 FATAL("Module %s defined with ambiguous global tagging mode",
160                         arg->mod->ModuleName);
161                 RET2RVAL(-1, rvalue);
162         }
163
164         switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
165         case MSF_NOFLAGS:
166                 /*
167                  * arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
168                  */
169                 break;
170         case MSF_unk_INSTRUCTIONS:
171                 WARNING("Module %s defined with unrecognized "
172                         "encoding reference", arg->mod->ModuleName);
173                 RET2RVAL(1, rvalue);
174                 /* Fall through */
175         case MSF_TAG_INSTRUCTIONS:
176         case MSF_XER_INSTRUCTIONS:
177                 break;
178         default:
179                 FATAL("Module %s defined with ambiguous encoding reference",
180                         arg->mod->ModuleName);
181                 RET2RVAL(-1, rvalue);
182         }
183
184         /*
185          * Do various non-recursive transformations.
186          */
187         TQ_FOR(expr, &(arg->mod->members), next) {
188                 arg->expr = expr;
189                 ret = phase_1_1(arg, 0);
190                 RET2RVAL(ret, rvalue);
191                 /*
192                  * Make sure everybody's behaving well.
193                  */
194                 assert(arg->expr == expr);
195         }
196         TQ_FOR(expr, &(arg->mod->members), next) {
197                 arg->expr = expr;
198                 ret = phase_1_1(arg, 1);
199                 RET2RVAL(ret, rvalue);
200                 assert(arg->expr == expr);
201         }
202
203
204
205         /*
206          * 5. Automatic tagging
207          */
208         TQ_FOR(expr, &(arg->mod->members), next) {
209
210                 arg->expr = expr;
211
212                 ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
213                 RET2RVAL(ret, rvalue);
214
215                 assert(arg->expr == expr);
216         }
217
218         /*
219          * 8. fix BIT STRING
220          * 9. fix spaces in cstrings
221          */
222         TQ_FOR(expr, &(arg->mod->members), next) {
223                 arg->expr = expr;
224
225                 ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
226                 RET2RVAL(ret, rvalue);
227
228                 ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
229                 RET2RVAL(ret, rvalue);
230
231                 assert(arg->expr == expr);
232         }
233
234         /*
235          * ... Check for tags distinctness.
236          */
237         TQ_FOR(expr, &(arg->mod->members), next) {
238                 arg->expr = expr;
239
240                 ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
241                 RET2RVAL(ret, rvalue);
242
243                 assert(arg->expr == expr);
244         }
245
246         return rvalue;
247 }
248
249 static int
250 asn1f_fix_module__phase_2(arg_t *arg) {
251         asn1p_expr_t *expr;
252         int rvalue = 0;
253         int ret;
254
255         TQ_FOR(expr, &(arg->mod->members), next) {
256
257                 arg->expr = expr;
258
259                 /*
260                  * Dereference DEFAULT values.
261                  */
262                 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_defaults);
263                 RET2RVAL(ret, rvalue);
264
265                 /*
266                  * Resolve references in constraints (the second pass).
267                  */
268                 ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
269                 RET2RVAL(ret, rvalue);
270
271                 /*
272                  * Check semantic validity of constraints.
273                  */
274                 ret = asn1f_recurse_expr(arg, asn1f_check_constraints);
275                 RET2RVAL(ret, rvalue);
276
277                 /*
278                  * Uniquely tag each inner type.
279                  */
280                 asn1f_apply_unique_index(0);
281                 ret = asn1f_recurse_expr(arg, asn1f_apply_unique_index);
282                 RET2RVAL(ret, rvalue);
283
284                 assert(arg->expr == expr);
285         }
286
287         return rvalue;
288 }
289
290 static int
291 phase_1_1(arg_t *arg, int prm2) {
292         asn1p_expr_t *expr = arg->expr;
293         int rvalue = 0;
294         int ret;
295
296         if(expr->lhs_params && expr->spec_index == -1) {
297                 int i;
298                 if(!prm2)
299                         /* Do not process the parameterized type just yet */
300                         return 0;
301                 for(i = 0; i < expr->specializations.pspecs_count; i++) {
302                         arg->expr = expr->specializations.pspec[i].my_clone;
303                         ret = phase_1_1(arg, 0);
304                         RET2RVAL(ret, rvalue);
305                 }
306                 arg->expr = expr;       /* revert */
307                 return rvalue;
308         } else if(prm2) {
309                 return 0;       /* Already done! */
310         }
311
312         /* Check whether this type is a duplicate */
313         if(!expr->lhs_params) {
314                 ret = asn1f_check_duplicate(arg);
315                 RET2RVAL(ret, rvalue);
316         }
317
318         DEBUG("=== Now processing \"%s\" (%d/0x%x) at line %d ===",
319                 expr->Identifier, expr->meta_type, expr->expr_type,
320                 expr->_lineno);
321         assert(expr->meta_type != AMT_INVALID);
322
323         /*
324          * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
325          */
326         ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
327         RET2RVAL(ret, rvalue);
328
329         /*
330          * 2.5.4
331          */
332         ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
333         RET2RVAL(ret, rvalue);
334
335         /*
336          * Fix tagging of top-level types.
337          */
338         ret = asn1f_fix_constr_tag(arg, 1);
339         RET2RVAL(ret, rvalue);
340
341         /*
342          * 2.[234] Process SEQUENCE/SET/CHOICE types.
343          */
344         ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
345         RET2RVAL(ret, rvalue);
346
347         /*
348          * 2.5.5
349          */
350         ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
351         RET2RVAL(ret, rvalue);
352
353         /*
354          * Resolve references in constraints.
355          */
356         ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
357         RET2RVAL(ret, rvalue);
358
359         /*
360          * Parse class information object sets.
361          */
362         ret = asn1f_parse_class_object(arg);
363         RET2RVAL(ret, rvalue);
364
365         /*
366          * 6. INTEGER value processed at 2.5.4.
367          */
368
369         return rvalue;
370 }
371
372 static int
373 asn1f_fix_simple(arg_t *arg) {
374         int rvalue = 0;
375         int ret;
376
377         ret = asn1f_fix_enum(arg);
378         RET2RVAL(ret, rvalue);
379
380         ret = asn1f_fix_integer(arg);
381         RET2RVAL(ret, rvalue);
382
383         return rvalue;
384 }
385
386 static int
387 asn1f_fix_constructed(arg_t *arg) {
388         int rvalue = 0;
389         int ret;
390
391         switch(arg->expr->expr_type) {
392         case ASN_CONSTR_SEQUENCE:
393         case ASN_CONSTR_SET:
394         case ASN_CONSTR_CHOICE:
395                 break;
396         default:
397                 return 0;
398         }
399
400         /* Check identifier distinctness */
401         ret = asn1f_check_unique_expr(arg);
402         RET2RVAL(ret, rvalue);
403
404         /* Fix extensibility */
405         ret = asn1f_fix_constr_ext(arg);
406         RET2RVAL(ret, rvalue);
407
408         /* Fix tagging */
409         ret = asn1f_fix_constr_tag(arg, 0);
410         RET2RVAL(ret, rvalue);
411
412         /* Import COMPONENTS OF stuff */
413         ret = asn1f_pull_components_of(arg);
414         RET2RVAL(ret, rvalue);
415
416         return rvalue;
417 }
418
419 static int
420 asn1f_resolve_constraints(arg_t *arg) {
421         asn1p_expr_t *top_parent;
422         asn1p_expr_type_e etype;
423         int rvalue = 0;
424         int ret;
425
426         top_parent = asn1f_find_terminal_type(arg, arg->expr);
427         if(top_parent)
428                 etype = top_parent->expr_type;
429         else    etype = A1TC_INVALID;
430
431         DEBUG("(%s)", arg->expr->Identifier);
432
433     ret = asn1constraint_resolve(arg, arg->expr->constraints, etype, 0);
434     RET2RVAL(ret, rvalue);
435
436         return rvalue;
437 }
438
439 static int
440 asn1f_check_constraints(arg_t *arg) {
441         static enum asn1p_constraint_type_e test_types[] = {
442                 ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
443         asn1p_expr_t *top_parent;
444         asn1cnst_range_t *range;
445         asn1p_expr_type_e etype;
446         unsigned int i;
447         int rvalue = 0;
448         int ret;
449
450         DEBUG("(%s{%d/%d})",
451                 arg->expr->Identifier,
452                 arg->expr->meta_type, arg->expr->expr_type);
453
454         top_parent = asn1f_find_terminal_type(arg, arg->expr);
455         if(!top_parent)
456                 return 0;
457         etype = top_parent->expr_type;
458
459         ret = asn1constraint_pullup(arg);
460         RET2RVAL(ret, rvalue);
461
462         for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
463                 range = asn1constraint_compute_constraint_range(
464                                 arg->expr->Identifier,
465                                 etype,
466                                 arg->expr->combined_constraints,
467                                 test_types[i], 0, 0,
468                                 CPR_noflags /* ignore -fbless-SIZE */);
469                 if(!range && errno == EPERM) {
470                         FATAL("This error happened for \"%s\" (meta %d) "
471                                 "at line %d",
472                                 arg->expr->Identifier,
473                                 arg->expr->meta_type,
474                                 arg->expr->_lineno);
475                         return -1;
476                 }
477                 asn1constraint_range_free(range);
478         }
479
480         return rvalue;
481 }
482
483 static int
484 asn1f_check_duplicate(arg_t *arg) {
485         arg_t tmparg = *arg;
486         int rvalue = 0;
487
488         /*
489          * This is a linear scan in search of a similar type.
490          * The linear scan is just fine for the task, no need to over-optimize.
491          */
492         TQ_FOR(tmparg.mod, &arg->asn->modules, mod_next) {
493                 int critical = 1;       /* FATAL */
494
495                 if((arg->mod->_tags & MT_STANDARD_MODULE)
496                 != (tmparg.mod->_tags & MT_STANDARD_MODULE)) {
497                         /* Ignore clashes with standard module */
498                         critical = 0;   /* WARNING */
499                 }
500
501                 TQ_FOR(tmparg.expr, &(tmparg.mod->members), next) {
502                         int diff_files; /* different files */
503
504                         assert(tmparg.expr->Identifier);
505                         assert(arg->expr->Identifier);
506
507                         if(arg->expr->spec_index != -1)
508                                 continue;
509
510                         if(tmparg.expr == arg->expr) break;
511
512                         if(strcmp(tmparg.expr->Identifier,
513                                   arg->expr->Identifier))
514                                 continue;
515
516                         /* resolve clash of Identifier in different modules */
517                         int oid_exist = (tmparg.expr->module->module_oid && arg->expr->module->module_oid);
518                         if ((!oid_exist && strcmp(tmparg.expr->module->ModuleName, arg->expr->module->ModuleName)) ||
519                                 (oid_exist && !asn1p_oid_compare(tmparg.expr->module->module_oid, arg->expr->module->module_oid))) {
520
521                                 tmparg.expr->_mark |= TM_NAMECLASH;
522                                 arg->expr->_mark |= TM_NAMECLASH;
523                                 continue;
524                         }
525
526                         diff_files = strcmp(arg->mod->source_file_name,
527                                         tmparg.mod->source_file_name) ? 1 : 0;
528
529                         LOG(critical,
530                         "ASN.1 expression \"%s\" at line %d of module %s\n"
531                         "clashes with expression \"%s\" at line %d of module %s"
532                         "%s%s%s.\n"
533                         "Rename or remove either instance "
534                                 "to resolve the conflict",
535                                 arg->expr->Identifier,
536                                 arg->expr->_lineno,
537                                 arg->mod->ModuleName,
538                                 tmparg.expr->Identifier,
539                                 tmparg.expr->_lineno,
540                                 tmparg.mod->ModuleName,
541                                 diff_files ? " (" : "",
542                                 diff_files ? tmparg.mod->source_file_name : "",
543                                 diff_files ? ")" : "");
544                         if(critical)
545                                 return -1;
546                         RET2RVAL(1, rvalue);
547                 }
548                 if(tmparg.mod == arg->mod) break;
549         }
550
551         return rvalue;
552 }
553
554 static int
555 asn1f_apply_unique_index(arg_t *arg) {
556         static int unique_index;
557         if(!arg) { unique_index = 0; return 0; }
558
559         arg->expr->_type_unique_index = ++unique_index;
560
561         return 0;
562 }
563
564 /*
565  * Print everything to stderr
566  */
567 static void
568 _default_error_logger(int _severity, const char *fmt, ...) {
569         va_list ap;
570         char *pfx = "";
571
572         switch(_severity) {
573         case -1: pfx = "DEBUG: "; break;
574         case 0: pfx = "WARNING: "; break;
575         case 1: pfx = "FATAL: "; break;
576         }
577         
578         fprintf(stderr, "%s", pfx);
579         va_start(ap, fmt);
580         vfprintf(stderr, fmt, ap);
581         va_end(ap);
582         fprintf(stderr, "\n");
583 }