NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1compiler / asn1c_misc.c
1 #include "asn1c_internal.h"
2 #include "asn1c_misc.h"
3
4 #include <asn1fix_crange.h>     /* constraint groker from libasn1fix */
5 #include <asn1fix_export.h>     /* other exportable stuff from libasn1fix */
6
7 /*
8  * Checks that the given string is not a reserved C/C++ keyword [1],[2].
9  * _* keywords not included, since asn1 identifiers cannot begin with hyphen [3]
10  * [1] ISO/IEC 9899:2011 (C11), 6.4.1
11  * [2] ISO/IEC 14882:2014 (C++14), 2.12
12  * [3] ISO/IEC 8824-1:2003 (asn1) 11.3
13  */
14 static char *res_kwd[] = {
15                 /* C */
16         "auto", "break", "case", "char", "const", "continue", "default", "do",
17         "double", "else", "enum", "extern", "float", "for", "goto", "if",
18         "inline", "int", "long", "register", "restrict", "return", "short",
19         "signed", "sizeof", "static", "struct", "switch", "typedef", "union",
20         "unsigned", "void", "volatile", "while",
21                 /* C++ */
22         "alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool",
23         "catch", "char16_t", "char32_t", "class", "compl", "const_cast",
24         "constexpr", "decltype", "delete", "delete", "dynamic_cast",
25         "explicit", "export", "false", "friend", "mutable", "namespace", "new",
26         "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
27         "private", "protected", "public", "reinterpret_cast", "static_assert",
28         "static_cast", "template", "this", "thread_local", "throw", "true", "try",
29         "typeid", "typename", "using", "virtual", "wchar_t", "xor", "xor_eq"
30 };
31 static int
32 reserved_keyword(const char *str) {
33         size_t i;
34         for(i = 0 ; i < sizeof(res_kwd)/sizeof(res_kwd[0]); i++) {
35                 if(strcmp(str, res_kwd[i]) == 0)
36                         return 1;
37         }
38         return 0;
39 }
40
41 const char *
42 asn1c_prefix()
43 {
44         const char *prefix = getenv("ASN1C_PREFIX");
45
46         if(!prefix) prefix = "";
47
48         return prefix;
49 }
50
51 /*
52  * Construct identifier from multiple parts.
53  * Convert unsafe characters to underscores.
54  */
55 const char *
56 asn1c_make_identifier(enum ami_flags_e flags, asn1p_expr_t *expr, ...) {
57         static char *storage;
58         static int storage_size;
59         int nodelimiter = 0;
60         va_list ap;
61         char *str;
62         char *nextstr;
63         char *first = 0;
64         ssize_t size = 0;
65         char *p;
66         const char *prefix = NULL;
67         char *sptr[4], **psptr = &sptr[0];
68         int sptr_cnt = 0;
69
70         if(flags & AMI_USE_PREFIX)
71                 prefix = asn1c_prefix();
72
73         if(expr) {
74                 /*
75                  * Estimate the necessary storage size
76                  */
77                 if(expr->Identifier == NULL)
78                         return "Member";
79                 /*
80                  * Add MODULE name to resolve clash
81                  */
82                 if(expr->_mark & TM_NAMECLASH) {
83                         size += strlen(expr->module->ModuleName) + 2;
84                         sptr[sptr_cnt++] = expr->module->ModuleName;
85                 }
86                 sptr[sptr_cnt++] = expr->Identifier;
87
88                 size += strlen(expr->Identifier);
89                 if(expr->spec_index != -1 && expr->_lineno) {
90                         static char buf[32];
91                         size += 1 + snprintf(buf, sizeof buf, "%dP%d",
92                                 expr->_lineno, expr->spec_index);
93                         sptr[sptr_cnt++] = (char *)&buf;
94                 }
95         } else {
96                 size = -1;
97         }
98         sptr[sptr_cnt++] = (char *)0;
99
100         va_start(ap, expr);
101         while((str = va_arg(ap, char *)))
102                 size += 1 + strlen(str);
103         va_end(ap);
104         if(size == -1) return NULL;
105
106         if(prefix)
107                 size += 1 + strlen(prefix);
108         /*
109          * Make sure we have the required amount of storage.
110          */
111         if(storage_size <= size) {
112         char *tmp = malloc(size + 1);
113         if(tmp) {
114             free(storage);
115             storage = tmp;
116             storage_size = size + 1;
117         } else {
118             return NULL;
119         }
120         }
121
122         /*
123          * Fill-in the storage.
124          */
125         va_start(ap, expr);
126         p = storage;
127         if(prefix) {
128                 strcpy(storage, prefix);
129                 p += strlen(prefix);
130                 nodelimiter = 1;
131         }
132         nextstr = "";
133         for(str = 0; str || nextstr; str = nextstr) {
134                 int subst_made = 0;
135                 nextstr = *(psptr) ? *(psptr++) : va_arg(ap, char *);
136
137                 if(str == 0) {
138                         str = first = nextstr;
139                         nextstr = *(psptr) ? *(psptr++) : va_arg(ap, char *);
140                         if (!first) continue;
141                 }
142
143                 if(str[0] == '\0') {
144                         nodelimiter = 1;        /* No delimiter */
145                         continue;
146                 }
147
148                 if(str[0] == ' ' && str[1] == '\0') {
149                         *p++ = ' ';
150                         nodelimiter = 1;        /* No delimiter */
151                         continue;
152                 }
153
154                 if(str != first && !nodelimiter && !(flags & AMI_NODELIMITER))
155                         *p++ = '_';     /* Delimiter between tokens */
156                 nodelimiter = 0;
157
158                 /*
159                  * If it is a single argument, check that it does not clash
160                  * with C/C++ language keywords.
161                  */
162                 if((flags & AMI_CHECK_RESERVED)
163                 && str == first && !nextstr && reserved_keyword(str)) {
164                         *p++ = toupper(*str++);
165                         /* Fall through */
166                 }
167
168                 for(; *str; str++) {
169                         if(isalnum(*str)) {
170                                 *p++ = *str;
171                                 subst_made = 0;
172                         } else if(!subst_made++) {
173                                 if((flags & AMI_MASK_ONLY_SPACES)
174                                                 && !isspace(*str)) {
175                                         *p ++ = *str;
176                                 } else {
177                                         *p++ = '_';
178                                 }
179                         }
180                 }
181         }
182         va_end(ap);
183         *p = '\0';
184
185         assert((p - storage) <= storage_size);
186
187         return storage;
188 }
189
190 const char *
191 asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
192         asn1p_expr_t *exprid = 0;
193         asn1p_expr_t *top_parent;
194         asn1p_expr_t *terminal = 0;
195         int stdname = 0;
196         const char *typename;
197         const char *prefix;
198
199         /* Rewind to the topmost parent expression */
200         if((top_parent = expr->parent_expr))
201                 while(top_parent->parent_expr)
202                         top_parent = top_parent->parent_expr;
203
204         if(0) DEBUG("asn1c_type_name(%s: 0x%x)",
205                 expr->Identifier, expr->expr_type);
206
207         switch(expr->expr_type) {
208         case A1TC_REFERENCE:
209                 typename = expr->reference->components[
210                         expr->reference->comp_count-1].name;
211                 if(typename[0] == '&') {
212                         arg_t tmp = *arg;
213
214                         /*
215                          * This is a reference to a type defined in a class.
216                          * Resolve it and use instead.
217                          */
218             tmp.expr = WITH_MODULE_NAMESPACE(
219                 arg->expr->module, expr_ns,
220                 asn1f_class_access_ex(arg->asn, arg->expr->module, expr_ns,
221                                       arg->expr, expr->rhs_pspecs,
222                                       expr->reference));
223             if(!tmp.expr) return NULL;
224
225                         return asn1c_type_name(&tmp, tmp.expr, _format);
226                 }
227
228         terminal = WITH_MODULE_NAMESPACE(
229             expr->module, expr_ns,
230             (expr->meta_type == AMT_TYPEREF) ? 
231                 asn1f_lookup_symbol_ex(arg->asn, expr_ns, expr, expr->reference) :
232                 asn1f_find_terminal_type_ex(arg->asn, expr_ns, expr));
233
234         if(_format == TNF_RSAFE) {
235                         if(terminal && terminal->expr_type & ASN_CONSTR_MASK) {
236                                 typename = terminal->Identifier;
237                         }
238                 }
239
240                 if(_format == TNF_CTYPE || _format == TNF_CONSTYPE) {
241                         /*
242                          * If the component references the type itself,
243                          * switch to a recursion-safe type naming
244                          * ("struct foo" instead of "foo_t").
245                          */
246                         if(terminal && terminal == top_parent) {
247                                 _format = TNF_RSAFE;
248                         }
249                 }
250
251                 if(_format != TNF_RSAFE  && terminal && ((terminal->spec_index != -1) || (terminal->_mark & TM_NAMECLASH))) {
252                         exprid = terminal;
253                         typename = 0;
254                 }
255
256                 break;
257         case ASN_BASIC_INTEGER:
258         case ASN_BASIC_ENUMERATED:
259         case ASN_BASIC_REAL:
260         if((expr->expr_type == ASN_BASIC_REAL
261             && (_format == TNF_CONSTYPE || !(arg->flags & A1C_USE_WIDE_TYPES)
262                 || asn1c_REAL_fits(arg, expr) != RL_NOTFIT))
263            || asn1c_type_fits_long(arg, expr)) {
264             switch(_format) {
265                         case TNF_CONSTYPE:
266                                 if(expr->expr_type == ASN_BASIC_REAL) {
267                     return "double";
268                 } else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
269                     return "unsigned long";
270                 } else {
271                     return "long";
272                 }
273             case TNF_CTYPE:
274             case TNF_RSAFE:
275                 if(expr->expr_type == ASN_BASIC_REAL) {
276                     asn1cnst_range_t *range = asn1constraint_compute_OER_range(
277                         expr->Identifier, ASN_BASIC_REAL,
278                         expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
279                     if(range->narrowing == NARROW_FLOAT32) {
280                         asn1constraint_range_free(range);
281                         return "float";
282                     } else {
283                         asn1constraint_range_free(range);
284                         return "double";
285                     }
286                 } else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
287                     return "unsigned long";
288                 } else {
289                     return "long";
290                 }
291             default:
292                                 typename = 0;
293                                 switch(expr->expr_type) {
294                                 case ASN_BASIC_INTEGER:
295                                         typename = "NativeInteger"; break;
296                                 case ASN_BASIC_ENUMERATED:
297                                         typename = "NativeEnumerated"; break;
298                                 case ASN_BASIC_REAL:
299                                         typename = "NativeReal"; break;
300                                 default:
301                                         break;
302                                 }
303                                 break;
304                         }
305                         if(typename) {
306                                 if(_format != TNF_INCLUDE)
307                                         return typename;
308                                 stdname = 1;
309                                 break;
310                         }
311                 }
312                 /* Fall through */
313         default:
314                 if(expr->expr_type
315                 & (ASN_CONSTR_MASK | ASN_BASIC_MASK | ASN_STRING_MASK)) {
316                         if(_format == TNF_RSAFE)
317                                 _format = TNF_CTYPE;
318                         stdname = 1;
319                         typename = ASN_EXPR_TYPE2STR(expr->expr_type);
320                         if(_format == TNF_INCLUDE) {
321                                 if(expr->expr_type == ASN_CONSTR_SEQUENCE)
322                                         typename = "constr_SEQUENCE";
323                                 else if(expr->expr_type == ASN_CONSTR_CHOICE)
324                                         typename = "constr_CHOICE";
325                                 else if(expr->expr_type == ASN_CONSTR_SET)
326                                         typename = "constr_SET";
327                                 else if(expr->expr_type == ASN_CONSTR_SEQUENCE_OF)
328                                         typename = "constr_SEQUENCE_OF";
329                                 else if(expr->expr_type == ASN_CONSTR_SET_OF)
330                                         typename = "constr_SET_OF";
331                                 else if(expr->expr_type == ASN_CONSTR_OPEN_TYPE)
332                                         typename = "OPEN_TYPE";
333                         }
334                 } else {
335                         _format = TNF_RSAFE;
336                         typename = expr->Identifier;
337                 }
338         }
339
340         prefix = stdname ? "" : asn1c_prefix();
341
342         switch(_format) {
343         case TNF_UNMODIFIED:
344                 return asn1c_make_identifier(AMI_MASK_ONLY_SPACES | AMI_NODELIMITER | (stdname ? 0 : AMI_USE_PREFIX),
345                         0, prefix, MODULE_NAME_OF(exprid), exprid ? exprid->Identifier : typename, (char*)0);
346         case TNF_INCLUDE:
347                 return asn1c_make_identifier(
348                         AMI_MASK_ONLY_SPACES | AMI_NODELIMITER,
349                         0, ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
350                                 ? "\"" : "<"),
351                         prefix, MODULE_NAME_OF(exprid),
352                         exprid ? exprid->Identifier : typename,
353                         ((!stdname || (arg->flags & A1C_INCLUDES_QUOTED))
354                                 ? ".h\"" : ".h>"), (char*)0);
355         case TNF_SAFE:
356                 return asn1c_make_identifier(stdname ? 0 : AMI_USE_PREFIX, exprid, typename, (char*)0);
357         case TNF_CTYPE: /* C type */
358         case TNF_CONSTYPE:      /* C type */
359                 return asn1c_make_identifier(stdname ? 0 : AMI_USE_PREFIX, exprid,
360                                 exprid?"t":typename, exprid?0:"t", (char*)0);
361         case TNF_RSAFE: /* Recursion-safe type */
362                 return asn1c_make_identifier(AMI_CHECK_RESERVED | AMI_NODELIMITER, 0,
363                         "struct", " ", prefix, MODULE_NAME_OF(exprid), typename, (char*)0);
364         }
365
366         assert(!"unreachable");
367         return typename;
368 }
369
370 static asn1p_expr_type_e
371 expr_get_type(arg_t *arg, asn1p_expr_t *expr) {
372         asn1p_expr_t *terminal;
373         terminal = asn1f_find_terminal_type_ex(arg->asn, arg->ns, expr);
374         if(terminal) return terminal->expr_type;
375         return A1TC_INVALID;
376 }
377
378 enum asn1c_fitsfloat_e
379 asn1c_REAL_fits(arg_t *arg, asn1p_expr_t *expr) {
380     asn1p_expr_type_e etype = expr_get_type(arg, arg->expr);
381     if(etype == ASN_BASIC_REAL) {
382         asn1cnst_range_t *range = asn1constraint_compute_OER_range(
383             expr->Identifier, etype, expr->combined_constraints, ACT_EL_RANGE,
384             0, 0, 0);
385         enum asn1c_fitsfloat_e fits;
386         switch(range->narrowing) {
387         case NARROW_FLOAT32:
388             fits = RL_FITS_FLOAT32;
389             break;
390         case NARROW_DOUBLE64:
391             fits = RL_FITS_DOUBLE64;
392             break;
393         default:
394             fits = RL_NOTFIT;
395             break;
396         }
397         asn1constraint_range_free(range);
398         return fits;
399     } else {
400         return 0;
401     }
402 }
403
404 /*
405  * Check whether the specified INTEGER or ENUMERATED type can be represented
406  * using the generic 'long' or 'unsigned long' type.
407  */
408 enum asn1c_fitslong_e
409 asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
410         asn1cnst_range_t *range = 0;
411         asn1cnst_edge_t left;
412         asn1cnst_edge_t right;
413         asn1p_expr_t *v;
414
415 /*
416  * Since we don't know the sizeof(long) on the possible target platform
417  * which will be compiling the code generated by asn1c, let's play it
418  * simple: long's range is equal to or greater than int32_t.
419  * NOTE: the most negative integer cannot be written in C, as the C99
420  * standard will give it an unsigned type.
421  * It is defined here as a constant expression.
422  */
423 #define RIGHTMAX        2147483647      /* of 32-bit integer type */
424 #define LEFTMIN         (-RIGHTMAX-1)   /* of 32-bit integer type */
425
426         /* Descend to the terminal type */
427     expr = WITH_MODULE_NAMESPACE(
428         expr->module, expr_ns,
429         asn1f_find_terminal_type_ex(arg->asn, expr_ns, expr));
430     if(expr == 0) return FL_NOTFIT;
431
432         /* The "fits into long" operation is relevant only for integer types */
433         switch(expr->expr_type) {
434         case ASN_BASIC_INTEGER:
435         case ASN_BASIC_ENUMERATED:
436                 break;
437         default:
438                 return FL_NOTFIT;
439         }
440
441         /*
442          * First, evaluate the range of explicitly given identifiers.
443          */
444         TQ_FOR(v, &(expr->members), next) {
445                 if(v->expr_type != A1TC_UNIVERVAL)
446                         continue;
447                 if(v->value->value.v_integer < LEFTMIN
448                 || v->value->value.v_integer > RIGHTMAX)
449                         return FL_NOTFIT;
450         }
451
452         if(!expr->combined_constraints) 
453                 return (arg->flags & A1C_USE_WIDE_TYPES)
454                         ? FL_NOTFIT : FL_PRESUMED;
455
456         /*
457          * Second, if -fbless-SIZE is given, the (SIZE()) constraint may be
458          * applied (non-standard! but we can deal with this) to the type.
459          * Check the range.
460          */
461         range = asn1constraint_compute_constraint_range(expr->Identifier,
462                 expr->expr_type,
463                 expr->combined_constraints, ACT_CT_SIZE, 0, 0,
464                 CPR_simulate_fbless_SIZE);
465         if(range) {
466                 if(!range->incompatible) {
467                         right = range->right;
468                         /* Use 4 instead of sizeof(long) is justified! */
469                         if(right.type == ARE_VALUE && right.value <= 4)
470                                 return FL_FITS_SIGNED;
471                 }
472                 asn1constraint_range_free(range);
473         }
474
475         /*
476          * Third, pull up the PER visible range of the INTEGER.
477          */
478         range = asn1constraint_compute_PER_range(expr->Identifier, expr->expr_type,
479                 expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
480
481         if(!range
482         /* Commenting out
483     || range->extensible
484      * because this may or may not indicate wide type.
485      */
486     || (range->extensible && (arg->flags & A1C_USE_WIDE_TYPES))
487         || range->empty_constraint
488         || range->incompatible
489         || range->not_PER_visible
490         ) {
491                 asn1constraint_range_free(range);
492                 return (arg->flags & A1C_USE_WIDE_TYPES)
493                         ? FL_NOTFIT : FL_PRESUMED;
494         }
495
496         left = range->left;
497         right = range->right;
498         asn1constraint_range_free(range);
499
500         /* Special case for unsigned */
501     if(!(arg->flags & A1C_USE_WIDE_TYPES) && left.type == ARE_VALUE
502        && left.value >= 0 && left.value <= 2147483647
503        && right.type == ARE_MAX) {
504         return FL_FITS_UNSIGN;
505     }
506     if(left.type == ARE_VALUE
507                 && left.value >= 0
508         && right.type == ARE_VALUE
509                 && right.value > 2147483647
510                 && right.value <= (asn1c_integer_t)(4294967295UL))
511                 return FL_FITS_UNSIGN;
512                 
513
514         /* If some fixed value is outside of target range, not fit */
515         if(left.type == ARE_VALUE
516                         && (left.value < LEFTMIN || left.value > RIGHTMAX))
517                 return FL_NOTFIT;
518         if(right.type == ARE_VALUE
519                         && (right.value > RIGHTMAX || right.value < LEFTMIN))
520                 return FL_NOTFIT;
521
522         /* If the range is open, fits only unless -fwide-types is given */
523         if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
524                 return (arg->flags & A1C_USE_WIDE_TYPES)
525                         ? FL_NOTFIT : FL_PRESUMED;
526         }
527
528         return FL_FITS_SIGNED;
529 }