| 86 | #define CHECK_NULL(ptr, ...) if ((ptr) == NULL) { __VA_ARGS__; return NULL; } |
| 87 | |
| 88 | static te_expr *new_expr(const int type, const te_expr *parameters[]) { |
| 89 | const int arity = ARITY(type); |
| 90 | const int psize = sizeof(void*) * arity; |
| 91 | |
| 92 | /* Calculate the size needed for the header (type, union member) and the actual parameters. */ |
| 93 | size_t actual_alloc_size = offsetof(te_expr, parameters) + psize; |
| 94 | |
| 95 | if (IS_CLOSURE(type)) { |
| 96 | actual_alloc_size += sizeof(void*); /* For the context pointer, typically stored after parameters. */ |
| 97 | } |
| 98 | |
| 99 | /* Ensure that the allocated size is at least sizeof(te_expr). |
| 100 | * This makes the te_expr* pointer valid for static analysis even if arity is 0, |
| 101 | * as sizeof(te_expr) includes the first element of the parameters array. |
| 102 | */ |
| 103 | if (actual_alloc_size < sizeof(te_expr)) { |
| 104 | actual_alloc_size = sizeof(te_expr); |
| 105 | } |
| 106 | |
| 107 | te_expr *ret = malloc(actual_alloc_size); |
| 108 | CHECK_NULL(ret); /* Handle malloc failure. */ |
| 109 | |
| 110 | memset(ret, 0, actual_alloc_size); |
| 111 | if (arity && parameters) { |
| 112 | memcpy(ret->parameters, parameters, psize); |
| 113 | } |
| 114 | ret->type = type; |
| 115 | ret->bound = 0; |
| 116 | return ret; |
| 117 | } |
| 118 | |
| 119 | |
| 120 | void te_free_parameters(te_expr *n) { |