vbscript: Add missing error handling in interp_jmp_false.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27
28 typedef struct {
29     vbscode_t *code;
30     instr_t *instr;
31     script_ctx_t *script;
32     function_t *func;
33
34     unsigned stack_size;
35     unsigned top;
36     VARIANT *stack;
37 } exec_ctx_t;
38
39 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
40
41 typedef enum {
42     REF_NONE,
43     REF_DISP,
44     REF_VAR
45 } ref_type_t;
46
47 typedef struct {
48     ref_type_t type;
49     union {
50         struct {
51             IDispatch *disp;
52             DISPID id;
53         } d;
54         VARIANT *v;
55     } u;
56 } ref_t;
57
58 typedef struct {
59     VARIANT *v;
60     VARIANT store;
61     BOOL owned;
62 } variant_val_t;
63
64 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
65 {
66     while(var) {
67         if(!strcmpiW(var->name, name)) {
68             ref->type = REF_VAR;
69             ref->u.v = &var->v;
70             return TRUE;
71         }
72
73         var = var->next;
74     }
75
76     return FALSE;
77 }
78
79 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
80 {
81     named_item_t *item;
82     DISPID id;
83     HRESULT hres;
84
85     if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
86         return S_OK;
87
88     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
89         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
90             hres = disp_get_id(item->disp, name, &id);
91             if(SUCCEEDED(hres)) {
92                 ref->type = REF_DISP;
93                 ref->u.d.disp = item->disp;
94                 ref->u.d.id = id;
95                 return S_OK;
96             }
97         }
98     }
99
100     if(!ctx->func->code_ctx->option_explicit)
101         FIXME("create an attempt to set\n");
102
103     ref->type = REF_NONE;
104     return S_OK;
105 }
106
107 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
108 {
109     assert(ctx->top);
110     return ctx->stack + --ctx->top;
111 }
112
113 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
114 {
115     if(ctx->stack_size == ctx->top) {
116         VARIANT *new_stack;
117
118         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
119         if(!new_stack) {
120             VariantClear(v);
121             return E_OUTOFMEMORY;
122         }
123
124         ctx->stack = new_stack;
125         ctx->stack_size *= 2;
126     }
127
128     ctx->stack[ctx->top++] = *v;
129     return S_OK;
130 }
131
132 static void stack_popn(exec_ctx_t *ctx, unsigned n)
133 {
134     while(n--)
135         VariantClear(stack_pop(ctx));
136 }
137
138 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
139 {
140     VARIANT *var;
141
142     var = stack_pop(ctx);
143
144     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
145         v->owned = FALSE;
146         var = V_VARIANTREF(var);
147     }else {
148         v->owned = TRUE;
149     }
150
151     if(V_VT(var) == VT_DISPATCH) {
152         FIXME("got dispatch - get its default value\n");
153         return E_NOTIMPL;
154     }else {
155         v->v = var;
156     }
157
158     return S_OK;
159 }
160
161 static inline void release_val(variant_val_t *v)
162 {
163     if(v->owned)
164         VariantClear(v->v);
165 }
166
167 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
168 {
169     VARIANT *v = stack_pop(ctx);
170
171     if(V_VT(v) == VT_DISPATCH) {
172         *ret = V_DISPATCH(v);
173         return S_OK;
174     }
175
176     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
177         FIXME("not supported type: %s\n", debugstr_variant(v));
178         VariantClear(v);
179         return E_FAIL;
180     }
181
182     v = V_BYREF(v);
183     if(V_VT(v) != VT_DISPATCH) {
184         FIXME("not disp %s\n", debugstr_variant(v));
185         return E_FAIL;
186     }
187
188     if(V_DISPATCH(v))
189         IDispatch_AddRef(V_DISPATCH(v));
190     *ret = V_DISPATCH(v);
191     return S_OK;
192 }
193
194 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
195 {
196     ctx->instr = ctx->code->instrs + addr;
197 }
198
199 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
200 {
201     dp->cArgs = arg_cnt;
202     dp->rgdispidNamedArgs = NULL;
203     dp->cNamedArgs = 0;
204
205     if(arg_cnt) {
206         VARIANT tmp;
207         unsigned i;
208
209         assert(ctx->top >= arg_cnt);
210
211         for(i=1; i*2 <= arg_cnt; i++) {
212             tmp = ctx->stack[ctx->top-i];
213             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
214             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
215         }
216
217         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
218     }else {
219         dp->rgvarg = NULL;
220     }
221 }
222
223 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
224 {
225     BSTR identifier = ctx->instr->arg1.bstr;
226     const unsigned arg_cnt = ctx->instr->arg2.uint;
227     ref_t ref = {0};
228     DISPPARAMS dp;
229     HRESULT hres;
230
231     hres = lookup_identifier(ctx, identifier, &ref);
232     if(FAILED(hres))
233         return hres;
234
235     vbstack_to_dp(ctx, arg_cnt, &dp);
236
237     switch(ref.type) {
238     case REF_VAR:
239         if(!res) {
240             FIXME("REF_VAR no res\n");
241             return E_NOTIMPL;
242         }
243
244         if(arg_cnt) {
245             FIXME("arguments not implemented\n");
246             return E_NOTIMPL;
247         }
248
249         V_VT(res) = VT_BYREF|VT_VARIANT;
250         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
251         break;
252     case REF_DISP:
253         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
254         if(FAILED(hres))
255             return hres;
256         break;
257     case REF_NONE:
258         FIXME("%s not found\n", debugstr_w(identifier));
259         return DISP_E_UNKNOWNNAME;
260     }
261
262     stack_popn(ctx, arg_cnt);
263     return S_OK;
264 }
265
266 static HRESULT interp_icall(exec_ctx_t *ctx)
267 {
268     VARIANT v;
269     HRESULT hres;
270
271     TRACE("\n");
272
273     hres = do_icall(ctx, &v);
274     if(FAILED(hres))
275         return hres;
276
277     return stack_push(ctx, &v);
278 }
279
280 static HRESULT interp_icallv(exec_ctx_t *ctx)
281 {
282     TRACE("\n");
283     return do_icall(ctx, NULL);
284 }
285
286 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
287 {
288     ref_t ref;
289     HRESULT hres;
290
291     hres = lookup_identifier(ctx, name, &ref);
292     if(FAILED(hres))
293         return hres;
294
295     switch(ref.type) {
296     case REF_VAR: {
297         VARIANT *v = ref.u.v;
298
299         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
300             v = V_VARIANTREF(v);
301
302         if(own_val) {
303             VariantClear(v);
304             *v = *val;
305             hres = S_OK;
306         }else {
307             hres = VariantCopy(v, val);
308         }
309         break;
310     }
311     case REF_DISP:
312         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
313         if(own_val)
314             VariantClear(val);
315         break;
316     case REF_NONE:
317         FIXME("%s not found\n", debugstr_w(name));
318         if(own_val)
319             VariantClear(val);
320         return DISP_E_UNKNOWNNAME;
321     }
322
323     return hres;
324 }
325
326 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
327 {
328     const BSTR arg = ctx->instr->arg1.bstr;
329     variant_val_t v;
330     HRESULT hres;
331
332     TRACE("%s\n", debugstr_w(arg));
333
334     hres = stack_pop_val(ctx, &v);
335     if(FAILED(hres))
336         return hres;
337
338     return assign_ident(ctx, arg, v.v, v.owned);
339 }
340
341 static HRESULT interp_assign_member(exec_ctx_t *ctx)
342 {
343     BSTR identifier = ctx->instr->arg1.bstr;
344     variant_val_t val;
345     IDispatch *obj;
346     DISPID id;
347     HRESULT hres;
348
349     TRACE("%s\n", debugstr_w(identifier));
350
351     hres = stack_pop_disp(ctx, &obj);
352     if(FAILED(hres))
353         return hres;
354
355     if(!obj) {
356         FIXME("NULL obj\n");
357         return E_FAIL;
358     }
359
360     hres = stack_pop_val(ctx, &val);
361     if(FAILED(hres)) {
362         IDispatch_Release(obj);
363         return hres;
364     }
365
366     hres = disp_get_id(obj, identifier, &id);
367     if(SUCCEEDED(hres))
368         hres = disp_propput(ctx->script, obj, id, val.v);
369
370     release_val(&val);
371     IDispatch_Release(obj);
372     return hres;
373 }
374
375 static HRESULT interp_jmp(exec_ctx_t *ctx)
376 {
377     const unsigned arg = ctx->instr->arg1.uint;
378
379     TRACE("%u\n", arg);
380
381     instr_jmp(ctx, arg);
382     return S_OK;
383 }
384
385 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
386 {
387     const unsigned arg = ctx->instr->arg1.uint;
388     variant_val_t val;
389     HRESULT hres;
390
391     TRACE("%u\n", arg);
392
393     hres = stack_pop_val(ctx, &val);
394     if(FAILED(hres))
395         return hres;
396
397     if(V_VT(val.v) != VT_BOOL) {
398         FIXME("unsupported for %s\n", debugstr_variant(val.v));
399         release_val(&val);
400         return E_NOTIMPL;
401     }
402
403     if(V_BOOL(val.v))
404         ctx->instr++;
405     else
406         instr_jmp(ctx, ctx->instr->arg1.uint);
407     return S_OK;
408 }
409
410 static HRESULT interp_ret(exec_ctx_t *ctx)
411 {
412     TRACE("\n");
413
414     ctx->instr = NULL;
415     return S_OK;
416 }
417
418 static HRESULT interp_bool(exec_ctx_t *ctx)
419 {
420     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
421     VARIANT v;
422
423     TRACE("%s\n", arg ? "true" : "false");
424
425     V_VT(&v) = VT_BOOL;
426     V_BOOL(&v) = arg;
427     return stack_push(ctx, &v);
428 }
429
430 static HRESULT interp_string(exec_ctx_t *ctx)
431 {
432     VARIANT v;
433
434     TRACE("\n");
435
436     V_VT(&v) = VT_BSTR;
437     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
438     if(!V_BSTR(&v))
439         return E_OUTOFMEMORY;
440
441     return stack_push(ctx, &v);
442 }
443
444 static HRESULT interp_long(exec_ctx_t *ctx)
445 {
446     const LONG arg = ctx->instr->arg1.lng;
447     VARIANT v;
448
449     TRACE("%d\n", arg);
450
451     V_VT(&v) = VT_I4;
452     V_I4(&v) = arg;
453     return stack_push(ctx, &v);
454 }
455
456 static HRESULT interp_short(exec_ctx_t *ctx)
457 {
458     const LONG arg = ctx->instr->arg1.lng;
459     VARIANT v;
460
461     TRACE("%d\n", arg);
462
463     V_VT(&v) = VT_I2;
464     V_I2(&v) = arg;
465     return stack_push(ctx, &v);
466 }
467
468 static HRESULT interp_double(exec_ctx_t *ctx)
469 {
470     const DOUBLE *arg = ctx->instr->arg1.dbl;
471     VARIANT v;
472
473     TRACE("%lf\n", *arg);
474
475     V_VT(&v) = VT_R8;
476     V_R8(&v) = *arg;
477     return stack_push(ctx, &v);
478 }
479
480 static HRESULT interp_empty(exec_ctx_t *ctx)
481 {
482     VARIANT v;
483
484     TRACE("\n");
485
486     V_VT(&v) = VT_EMPTY;
487     return stack_push(ctx, &v);
488 }
489
490 static HRESULT interp_null(exec_ctx_t *ctx)
491 {
492     VARIANT v;
493
494     TRACE("\n");
495
496     V_VT(&v) = VT_NULL;
497     return stack_push(ctx, &v);
498 }
499
500 static HRESULT interp_not(exec_ctx_t *ctx)
501 {
502     variant_val_t val;
503     VARIANT v;
504     HRESULT hres;
505
506     TRACE("\n");
507
508     hres = stack_pop_val(ctx, &val);
509     if(FAILED(hres))
510         return hres;
511
512     hres = VarNot(val.v, &v);
513     release_val(&val);
514     if(FAILED(hres))
515         return hres;
516
517     return stack_push(ctx, &v);
518 }
519
520 static HRESULT cmp_oper(exec_ctx_t *ctx)
521 {
522     variant_val_t l, r;
523     HRESULT hres;
524
525     hres = stack_pop_val(ctx, &r);
526     if(FAILED(hres))
527         return hres;
528
529     hres = stack_pop_val(ctx, &l);
530     if(SUCCEEDED(hres)) {
531         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
532             FIXME("comparing nulls is not implemented\n");
533             hres = E_NOTIMPL;
534         }else {
535             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
536         }
537     }
538
539     release_val(&r);
540     release_val(&l);
541     return hres;
542 }
543
544 static HRESULT interp_equal(exec_ctx_t *ctx)
545 {
546     VARIANT v;
547     HRESULT hres;
548
549     TRACE("\n");
550
551     hres = cmp_oper(ctx);
552     if(FAILED(hres))
553         return hres;
554
555     V_VT(&v) = VT_BOOL;
556     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
557     return stack_push(ctx, &v);
558 }
559
560 static HRESULT interp_nequal(exec_ctx_t *ctx)
561 {
562     VARIANT v;
563     HRESULT hres;
564
565     TRACE("\n");
566
567     hres = cmp_oper(ctx);
568     if(FAILED(hres))
569         return hres;
570
571     V_VT(&v) = VT_BOOL;
572     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
573     return stack_push(ctx, &v);
574 }
575
576 static HRESULT interp_concat(exec_ctx_t *ctx)
577 {
578     variant_val_t r, l;
579     VARIANT v;
580     HRESULT hres;
581
582     TRACE("\n");
583
584     hres = stack_pop_val(ctx, &r);
585     if(FAILED(hres))
586         return hres;
587
588     hres = stack_pop_val(ctx, &l);
589     if(SUCCEEDED(hres)) {
590         hres = VarCat(l.v, r.v, &v);
591         release_val(&l);
592     }
593     release_val(&r);
594     if(FAILED(hres))
595         return hres;
596
597     return stack_push(ctx, &v);
598 }
599
600 static HRESULT interp_add(exec_ctx_t *ctx)
601 {
602     variant_val_t r, l;
603     VARIANT v;
604     HRESULT hres;
605
606     TRACE("\n");
607
608     hres = stack_pop_val(ctx, &r);
609     if(FAILED(hres))
610         return hres;
611
612     hres = stack_pop_val(ctx, &l);
613     if(SUCCEEDED(hres)) {
614         hres = VarAdd(l.v, r.v, &v);
615         release_val(&l);
616     }
617     release_val(&r);
618     if(FAILED(hres))
619         return hres;
620
621     return stack_push(ctx, &v);
622 }
623
624 static HRESULT interp_sub(exec_ctx_t *ctx)
625 {
626     variant_val_t r, l;
627     VARIANT v;
628     HRESULT hres;
629
630     TRACE("\n");
631
632     hres = stack_pop_val(ctx, &r);
633     if(FAILED(hres))
634         return hres;
635
636     hres = stack_pop_val(ctx, &l);
637     if(SUCCEEDED(hres)) {
638         hres = VarSub(l.v, r.v, &v);
639         release_val(&l);
640     }
641     release_val(&r);
642     if(FAILED(hres))
643         return hres;
644
645     return stack_push(ctx, &v);
646 }
647
648 static HRESULT interp_mod(exec_ctx_t *ctx)
649 {
650     variant_val_t r, l;
651     VARIANT v;
652     HRESULT hres;
653
654     TRACE("\n");
655
656     hres = stack_pop_val(ctx, &r);
657     if(FAILED(hres))
658         return hres;
659
660     hres = stack_pop_val(ctx, &l);
661     if(SUCCEEDED(hres)) {
662         hres = VarMod(l.v, r.v, &v);
663         release_val(&l);
664     }
665     release_val(&r);
666     if(FAILED(hres))
667         return hres;
668
669     return stack_push(ctx, &v);
670 }
671
672 static HRESULT interp_idiv(exec_ctx_t *ctx)
673 {
674     variant_val_t r, l;
675     VARIANT v;
676     HRESULT hres;
677
678     TRACE("\n");
679
680     hres = stack_pop_val(ctx, &r);
681     if(FAILED(hres))
682         return hres;
683
684     hres = stack_pop_val(ctx, &l);
685     if(SUCCEEDED(hres)) {
686         hres = VarIdiv(l.v, r.v, &v);
687         release_val(&l);
688     }
689     release_val(&r);
690     if(FAILED(hres))
691         return hres;
692
693     return stack_push(ctx, &v);
694 }
695
696 static HRESULT interp_div(exec_ctx_t *ctx)
697 {
698     variant_val_t r, l;
699     VARIANT v;
700     HRESULT hres;
701
702     TRACE("\n");
703
704     hres = stack_pop_val(ctx, &r);
705     if(FAILED(hres))
706         return hres;
707
708     hres = stack_pop_val(ctx, &l);
709     if(SUCCEEDED(hres)) {
710         hres = VarDiv(l.v, r.v, &v);
711         release_val(&l);
712     }
713     release_val(&r);
714     if(FAILED(hres))
715         return hres;
716
717     return stack_push(ctx, &v);
718 }
719
720 static HRESULT interp_mul(exec_ctx_t *ctx)
721 {
722     variant_val_t r, l;
723     VARIANT v;
724     HRESULT hres;
725
726     TRACE("\n");
727
728     hres = stack_pop_val(ctx, &r);
729     if(FAILED(hres))
730         return hres;
731
732     hres = stack_pop_val(ctx, &l);
733     if(SUCCEEDED(hres)) {
734         hres = VarMul(l.v, r.v, &v);
735         release_val(&l);
736     }
737     release_val(&r);
738     if(FAILED(hres))
739         return hres;
740
741     return stack_push(ctx, &v);
742 }
743
744 static HRESULT interp_exp(exec_ctx_t *ctx)
745 {
746     variant_val_t r, l;
747     VARIANT v;
748     HRESULT hres;
749
750     TRACE("\n");
751
752     hres = stack_pop_val(ctx, &r);
753     if(FAILED(hres))
754         return hres;
755
756     hres = stack_pop_val(ctx, &l);
757     if(SUCCEEDED(hres)) {
758         hres = VarPow(l.v, r.v, &v);
759         release_val(&l);
760     }
761     release_val(&r);
762     if(FAILED(hres))
763         return hres;
764
765     return stack_push(ctx, &v);
766 }
767
768 static HRESULT interp_neg(exec_ctx_t *ctx)
769 {
770     variant_val_t val;
771     VARIANT v;
772     HRESULT hres;
773
774     hres = stack_pop_val(ctx, &val);
775     if(FAILED(hres))
776         return hres;
777
778     hres = VarNeg(val.v, &v);
779     release_val(&val);
780     if(FAILED(hres))
781         return hres;
782
783     return stack_push(ctx, &v);
784 }
785
786 static const instr_func_t op_funcs[] = {
787 #define X(x,n,a,b) interp_ ## x,
788 OP_LIST
789 #undef X
790 };
791
792 static const unsigned op_move[] = {
793 #define X(x,n,a,b) n,
794 OP_LIST
795 #undef X
796 };
797
798 HRESULT exec_script(script_ctx_t *ctx, function_t *func)
799 {
800     exec_ctx_t exec;
801     vbsop_t op;
802     HRESULT hres = S_OK;
803
804     exec.stack_size = 16;
805     exec.top = 0;
806     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
807     if(!exec.stack)
808         return E_OUTOFMEMORY;
809
810     exec.code = func->code_ctx;
811     exec.instr = exec.code->instrs + func->code_off;
812     exec.script = ctx;
813     exec.func = func;
814
815     while(exec.instr) {
816         op = exec.instr->op;
817         hres = op_funcs[op](&exec);
818         if(FAILED(hres)) {
819             FIXME("Failed %08x\n", hres);
820             stack_popn(&exec, exec.top);
821             break;
822         }
823
824         exec.instr += op_move[op];
825     }
826
827     assert(!exec.top);
828     heap_free(exec.stack);
829
830     return hres;
831 }