BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDEvaluator.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stddef.h>
31 #include <limits.h>
32  
33 #include <misc/debug.h>
34 #include <misc/balloc.h>
35 #include <base/BLog.h>
36 #include <ncd/make_name_indices.h>
37  
38 #include "NCDEvaluator.h"
39  
40 #include <generated/blog_channel_ncd.h>
41  
42 #define NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY 64
43 #define NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY 16
44  
45 #define MAX_LOCAL_IDS (NCDVAL_TOPPLID / 2)
46  
47 #include "NCDEvaluator_var_vec.h"
48 #include <structure/Vector_impl.h>
49  
50 #include "NCDEvaluator_call_vec.h"
51 #include <structure/Vector_impl.h>
52  
53 struct NCDEvaluator__eval_context {
54 NCDEvaluator *eval;
55 NCDEvaluator_EvalFuncs const *funcs;
56 };
57  
58 static int expr_init (struct NCDEvaluator__Expr *o, NCDEvaluator *eval, NCDValue *value);
59 static void expr_free (struct NCDEvaluator__Expr *o);
60 static int expr_eval (struct NCDEvaluator__Expr *o, struct NCDEvaluator__eval_context const *context, NCDValMem *out_newmem, NCDValRef *out_val);
61 static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out);
62 static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out);
63  
64 static int expr_init (struct NCDEvaluator__Expr *o, NCDEvaluator *eval, NCDValue *value)
65 {
66 ASSERT((NCDValue_Type(value), 1))
67  
68 NCDValMem_Init(&o->mem, eval->string_index);
69  
70 NCDValRef ref;
71 if (!add_expr_recurser(eval, value, &o->mem, &ref)) {
72 goto fail1;
73 }
74  
75 o->ref = NCDVal_ToSafe(ref);
76  
77 if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
78 if (!NCDValReplaceProg_Init(&o->prog, ref)) {
79 BLog(BLOG_ERROR, "NCDValReplaceProg_Init failed");
80 goto fail1;
81 }
82 }
83  
84 return 1;
85  
86 fail1:
87 NCDValMem_Free(&o->mem);
88 return 0;
89 }
90  
91 static void expr_free (struct NCDEvaluator__Expr *o)
92 {
93 if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
94 NCDValReplaceProg_Free(&o->prog);
95 }
96 NCDValMem_Free(&o->mem);
97 }
98  
99 static int expr_eval (struct NCDEvaluator__Expr *o, struct NCDEvaluator__eval_context const *context, NCDValMem *out_newmem, NCDValRef *out_val)
100 {
101 if (!NCDVal_IsSafeRefPlaceholder(o->ref)) {
102 if (!NCDValMem_InitCopy(out_newmem, &o->mem)) {
103 BLog(BLOG_ERROR, "NCDValMem_InitCopy failed");
104 goto fail0;
105 }
106  
107 if (!NCDValReplaceProg_Execute(o->prog, out_newmem, replace_placeholders_callback, (void *)context)) {
108 goto fail_free;
109 }
110  
111 *out_val = NCDVal_FromSafe(out_newmem, o->ref);
112 } else {
113 NCDValMem_Init(out_newmem, context->eval->string_index);
114  
115 NCDValRef ref;
116 if (!replace_placeholders_callback((void *)context, NCDVal_GetSafeRefPlaceholderId(o->ref), out_newmem, &ref) || NCDVal_IsInvalid(ref)) {
117 goto fail_free;
118 }
119  
120 *out_val = ref;
121 }
122  
123 return 1;
124  
125 fail_free:
126 NCDValMem_Free(out_newmem);
127 fail0:
128 return 0;
129 }
130  
131 static int add_expr_recurser (NCDEvaluator *o, NCDValue *value, NCDValMem *mem, NCDValRef *out)
132 {
133 switch (NCDValue_Type(value)) {
134 case NCDVALUE_STRING: {
135 const char *str = NCDValue_StringValue(value);
136 size_t len = NCDValue_StringLength(value);
137  
138 NCD_string_id_t string_id = NCDStringIndex_GetBin(o->string_index, str, len);
139 if (string_id < 0) {
140 BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
141 goto fail;
142 }
143  
144 *out = NCDVal_NewIdString(mem, string_id);
145 if (NCDVal_IsInvalid(*out)) {
146 goto fail;
147 }
148 } break;
149  
150 case NCDVALUE_LIST: {
151 *out = NCDVal_NewList(mem, NCDValue_ListCount(value));
152 if (NCDVal_IsInvalid(*out)) {
153 goto fail;
154 }
155  
156 for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) {
157 NCDValRef vval;
158 if (!add_expr_recurser(o, e, mem, &vval)) {
159 goto fail;
160 }
161  
162 if (!NCDVal_ListAppend(*out, vval)) {
163 BLog(BLOG_ERROR, "depth limit exceeded");
164 goto fail;
165 }
166 }
167 } break;
168  
169 case NCDVALUE_MAP: {
170 *out = NCDVal_NewMap(mem, NCDValue_MapCount(value));
171 if (NCDVal_IsInvalid(*out)) {
172 goto fail;
173 }
174  
175 for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
176 NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
177  
178 NCDValRef vkey;
179 NCDValRef vval;
180 if (!add_expr_recurser(o, ekey, mem, &vkey) ||
181 !add_expr_recurser(o, eval, mem, &vval)
182 ) {
183 goto fail;
184 }
185  
186 int inserted;
187 if (!NCDVal_MapInsert(*out, vkey, vval, &inserted)) {
188 BLog(BLOG_ERROR, "depth limit exceeded");
189 goto fail;
190 }
191 if (!inserted) {
192 BLog(BLOG_ERROR, "duplicate key in map");
193 goto fail;
194 }
195 }
196 } break;
197  
198 case NCDVALUE_VAR: {
199 struct NCDEvaluator__Var var;
200  
201 if (!ncd_make_name_indices(o->string_index, NCDValue_VarName(value), &var.varnames, &var.num_names)) {
202 BLog(BLOG_ERROR, "ncd_make_name_indices failed");
203 goto fail_var0;
204 }
205  
206 size_t index;
207 struct NCDEvaluator__Var *varptr = NCDEvaluator__VarVec_Push(&o->vars, &index);
208 if (!varptr) {
209 BLog(BLOG_ERROR, "NCDEvaluator__VarVec_Push failed");
210 goto fail_var1;
211 }
212  
213 if (index >= MAX_LOCAL_IDS) {
214 BLog(BLOG_ERROR, "too many variables");
215 goto fail_var2;
216 }
217  
218 *varptr = var;
219  
220 *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 0);
221 break;
222  
223 fail_var2:
224 NCDEvaluator__VarVec_Pop(&o->vars, NULL);
225 fail_var1:
226 BFree(var.varnames);
227 fail_var0:
228 goto fail;
229 } break;
230  
231 case NCDVALUE_INVOC: {
232 struct NCDEvaluator__Call call;
233  
234 NCDValue *func = NCDValue_InvocFunc(value);
235 if (NCDValue_Type(func) != NCDVALUE_STRING) {
236 BLog(BLOG_ERROR, "call function is not a string");
237 goto fail_invoc0;
238 }
239  
240 call.func_name_id = NCDStringIndex_GetBin(o->string_index, NCDValue_StringValue(func), NCDValue_StringLength(func));
241 if (call.func_name_id < 0) {
242 BLog(BLOG_ERROR, "NCDStringIndex_GetBin failed");
243 goto fail_invoc0;
244 }
245  
246 NCDValue *arg = NCDValue_InvocArg(value);
247 if (NCDValue_Type(arg) != NCDVALUE_LIST) {
248 BLog(BLOG_ERROR, "call argument is not a list literal!?");
249 goto fail_invoc0;
250 }
251  
252 if (!(call.args = BAllocArray(NCDValue_ListCount(arg), sizeof(call.args[0])))) {
253 BLog(BLOG_ERROR, "BAllocArray failed");
254 goto fail_invoc0;
255 }
256 call.num_args = 0;
257  
258 for (NCDValue *e = NCDValue_ListFirst(arg); e; e = NCDValue_ListNext(arg, e)) {
259 if (!expr_init(&call.args[call.num_args], o, e)) {
260 goto fail_invoc1;
261 }
262 call.num_args++;
263 }
264  
265 size_t index;
266 struct NCDEvaluator__Call *callptr = NCDEvaluator__CallVec_Push(&o->calls, &index);
267 if (!callptr) {
268 BLog(BLOG_ERROR, "NCDEvaluator__CallVec_Push failed");
269 goto fail_invoc1;
270 }
271  
272 if (index >= MAX_LOCAL_IDS) {
273 BLog(BLOG_ERROR, "too many variables");
274 goto fail_invoc2;
275 }
276  
277 *callptr = call;
278  
279 *out = NCDVal_NewPlaceholder(mem, ((int)index << 1) | 1);
280 break;
281  
282 fail_invoc2:
283 NCDEvaluator__CallVec_Pop(&o->calls, NULL);
284 fail_invoc1:
285 while (call.num_args-- > 0) {
286 expr_free(&call.args[call.num_args]);
287 }
288 BFree(call.args);
289 fail_invoc0:
290 goto fail;
291 } break;
292  
293 default: {
294 BLog(BLOG_ERROR, "expression type not supported");
295 goto fail;
296 } break;
297 }
298  
299 return 1;
300  
301 fail:
302 return 0;
303 }
304  
305 static int replace_placeholders_callback (void *arg, int plid, NCDValMem *mem, NCDValRef *out)
306 {
307 struct NCDEvaluator__eval_context const *context = arg;
308 NCDEvaluator *o = context->eval;
309  
310 int type = plid & 1;
311 int index = plid >> 1;
312  
313 ASSERT(index >= 0)
314 ASSERT(index < MAX_LOCAL_IDS)
315  
316 int res;
317  
318 switch (type) {
319 case 0: {
320 struct NCDEvaluator__Var *var = NCDEvaluator__VarVec_Get(&o->vars, index);
321  
322 res = context->funcs->func_eval_var(context->funcs->user, var->varnames, var->num_names, mem, out);
323 } break;
324  
325 case 1: {
326 struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->calls, index);
327  
328 NCDEvaluatorArgs args;
329 args.context = context;
330 args.call_index = index;
331  
332 res = context->funcs->func_eval_call(context->funcs->user, call->func_name_id, args, mem, out);
333 } break;
334  
335 default: {
336 ASSERT(0)
337 res = 0;
338 } break;
339 }
340  
341 ASSERT(res == 0 || res == 1)
342 return res;
343 }
344  
345 int NCDEvaluator_Init (NCDEvaluator *o, NCDStringIndex *string_index)
346 {
347 o->string_index = string_index;
348  
349 if (!NCDEvaluator__VarVec_Init(&o->vars, NCDEVALUATOR_DEFAULT_VARARRAY_CAPACITY)) {
350 BLog(BLOG_ERROR, "NCDEvaluator__VarVec_Init failed");
351 goto fail0;
352 }
353  
354 if (!NCDEvaluator__CallVec_Init(&o->calls, NCDEVALUATOR_DEFAULT_CALLARRAY_CAPACITY)) {
355 BLog(BLOG_ERROR, "NCDEvaluator__CallVec_Init failed");
356 goto fail1;
357 }
358  
359 return 1;
360  
361 fail1:
362 NCDEvaluator__VarVec_Free(&o->vars);
363 fail0:
364 return 0;
365 }
366  
367 void NCDEvaluator_Free (NCDEvaluator *o)
368 {
369 for (size_t i = 0; i < o->vars.count; i++) {
370 BFree(o->vars.elems[i].varnames);
371 }
372  
373 for (size_t i = 0; i < o->calls.count; i++) {
374 struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->calls, i);
375 while (call->num_args-- > 0) {
376 expr_free(&call->args[call->num_args]);
377 }
378 BFree(call->args);
379 }
380  
381 NCDEvaluator__CallVec_Free(&o->calls);
382 NCDEvaluator__VarVec_Free(&o->vars);
383 }
384  
385 int NCDEvaluatorExpr_Init (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDValue *value)
386 {
387 return expr_init(&o->expr, eval, value);
388 }
389  
390 void NCDEvaluatorExpr_Free (NCDEvaluatorExpr *o)
391 {
392 expr_free(&o->expr);
393 }
394  
395 int NCDEvaluatorExpr_Eval (NCDEvaluatorExpr *o, NCDEvaluator *eval, NCDEvaluator_EvalFuncs const *funcs, NCDValMem *out_newmem, NCDValRef *out_val)
396 {
397 ASSERT(funcs)
398 ASSERT(out_newmem)
399 ASSERT(out_val)
400  
401 struct NCDEvaluator__eval_context context;
402 context.eval = eval;
403 context.funcs = funcs;
404  
405 return expr_eval(&o->expr, &context, out_newmem, out_val);
406 }
407  
408 size_t NCDEvaluatorArgs_Count (NCDEvaluatorArgs *o)
409 {
410 struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->context->eval->calls, o->call_index);
411  
412 return call->num_args;
413 }
414  
415 int NCDEvaluatorArgs_EvalArgNewMem (NCDEvaluatorArgs *o, size_t index, NCDValMem *out_newmem, NCDValRef *out_ref)
416 {
417 struct NCDEvaluator__Call *call = NCDEvaluator__CallVec_Get(&o->context->eval->calls, o->call_index);
418 ASSERT(index < call->num_args)
419  
420 return expr_eval(&call->args[index], o->context, out_newmem, out_ref);
421 }
422  
423 int NCDEvaluatorArgs_EvalArg (NCDEvaluatorArgs *o, size_t index, NCDValMem *mem, NCDValRef *out_ref)
424 {
425 int res = 0;
426  
427 NCDValMem temp_mem;
428 NCDValRef temp_ref;
429 if (!NCDEvaluatorArgs_EvalArgNewMem(o, index, &temp_mem, &temp_ref)) {
430 goto fail0;
431 }
432  
433 NCDValRef ref = NCDVal_NewCopy(mem, temp_ref);
434 if (NCDVal_IsInvalid(ref)) {
435 goto fail1;
436 }
437  
438 *out_ref = ref;
439 res = 1;
440  
441 fail1:
442 NCDValMem_Free(&temp_mem);
443 fail0:
444 return res;
445 }