1 // vim: set ts=8 sts=2 sw=2 tw=99 et:
3 // This file is part of SourcePawn.
5 // SourcePawn is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // SourcePawn is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with SourcePawn. If not, see <http://www.gnu.org/licenses/>.
19 #include "interpreter.h"
21 #include "watchdog_timer.h"
23 #define STACK_MARGIN 64
25 using namespace SourcePawn;
28 IsValidOffset(uint32_t cip)
34 Read(const sp_plugin_t *plugin, cell_t offset)
36 return *reinterpret_cast<cell_t *>(plugin->memory + offset);
40 Write(const sp_plugin_t *plugin, cell_t offset, cell_t value)
42 *reinterpret_cast<cell_t *>(plugin->memory + offset) = value;
45 static inline cell_t *
46 Jump(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t target)
48 if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
49 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
53 return reinterpret_cast<cell_t *>(plugin->pcode + target);
56 static inline cell_t *
57 JumpTarget(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *cip, bool cond)
63 if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
64 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
68 cell_t *next = reinterpret_cast<cell_t *>(plugin->pcode + target);
69 if (next < cip && !g_WatchdogTimer.HandleInterrupt()) {
70 ctx->err = SP_ERROR_TIMEOUT;
78 CheckAddress(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *stk, cell_t addr)
80 if (uint32_t(addr) >= plugin->mem_size) {
81 ctx->err = SP_ERROR_MEMACCESS;
88 if (reinterpret_cast<cell_t *>(plugin->memory + addr) < stk) {
89 ctx->err = SP_ERROR_MEMACCESS;
97 PopTrackerAndSetHeap(BaseRuntime *rt)
99 sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
100 tracker_t *trk = ctx->tracker;
101 assert(trk->pCur > trk->pBase);
104 if (trk->pCur < trk->pBase)
105 return SP_ERROR_TRACKER_BOUNDS;
107 ucell_t amt = *trk->pCur;
108 if (amt > (ctx->hp - rt->plugin()->data_size))
109 return SP_ERROR_HEAPMIN;
112 return SP_ERROR_NONE;
116 PushTracker(sp_context_t *ctx, size_t amount)
118 tracker_t *trk = ctx->tracker;
120 if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
121 return SP_ERROR_TRACKER_BOUNDS;
123 if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) {
124 size_t disp = trk->size - 1;
126 trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
129 return SP_ERROR_TRACKER_BOUNDS;
131 trk->pCur = trk->pBase + disp;
134 *trk->pCur++ = amount;
135 return SP_ERROR_NONE;
139 NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
141 cell_t save_sp = ctx->sp;
142 cell_t save_hp = ctx->hp;
144 ctx->n_idx = native_idx;
146 sp_native_t *native = &ctx->plugin->natives[native_idx];
148 if (native->status == SP_NATIVE_UNBOUND) {
149 ctx->n_err = SP_ERROR_INVALID_NATIVE;
153 cell_t result = native->pfn(ctx->basecx, params);
155 if (ctx->n_err != SP_ERROR_NONE)
158 if (save_sp != ctx->sp) {
159 ctx->n_err = SP_ERROR_STACKLEAK;
162 if (save_hp != ctx->hp) {
163 ctx->n_err = SP_ERROR_HEAPLEAK;
171 BoundNativeCallback(sp_context_t *ctx, SPVM_NATIVE_FUNC pfn, cell_t *params)
173 cell_t save_sp = ctx->sp;
174 cell_t save_hp = ctx->hp;
176 cell_t result = pfn(ctx->basecx, params);
178 if (ctx->n_err != SP_ERROR_NONE)
181 if (save_sp != ctx->sp) {
182 ctx->n_err = SP_ERROR_STACKLEAK;
185 if (save_hp != ctx->hp) {
186 ctx->n_err = SP_ERROR_HEAPLEAK;
194 GenerateArray(BaseRuntime *rt, sp_context_t *ctx, cell_t dims, cell_t *stk, bool autozero)
197 uint32_t size = *stk;
198 if (size == 0 || !ke::IsUint32MultiplySafe(size, 4)) {
199 ctx->err = SP_ERROR_ARRAY_TOO_BIG;
204 uint32_t bytes = size * 4;
207 if (uintptr_t(ctx->plugin->memory + ctx->hp) >= uintptr_t(stk)) {
208 ctx->err = SP_ERROR_HEAPLOW;
212 if ((ctx->err = PushTracker(ctx, bytes)) != SP_ERROR_NONE)
216 memset(ctx->plugin->memory + ctx->hp, 0, bytes);
221 if ((ctx->err = GenerateFullArray(rt, dims, stk, autozero)) != SP_ERROR_NONE)
228 Interpret(BaseRuntime *rt, uint32_t aCodeStart, cell_t *rval)
230 const sp_plugin_t *plugin = rt->plugin();
231 cell_t *code = reinterpret_cast<cell_t *>(plugin->pcode);
232 cell_t *codeend = reinterpret_cast<cell_t *>(plugin->pcode + plugin->pcode_size);
234 if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size)
235 return SP_ERROR_INVALID_INSTRUCTION;
237 sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
238 ctx->err = SP_ERROR_NONE;
240 // Save the original frm. BaseContext won't, and if we error, we won't hit
241 // the stack unwinding code.
242 cell_t orig_frm = ctx->frm;
246 cell_t *cip = code + (aCodeStart / 4);
247 cell_t *stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
250 if (cip >= codeend) {
251 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
256 SpewOpcode(plugin, reinterpret_cast<cell_t *>(plugin->pcode + aCodeStart), cip);
259 OPCODE op = (OPCODE)*cip++;
278 Write(plugin, *cip++, 0);
282 Write(plugin, ctx->frm + *cip++, 0);
299 if (op >= OP_PUSH2_C)
300 n = ((op - OP_PUSH2_C) / 4) + 2;
316 if (op >= OP_PUSH2_ADR)
317 n = ((op - OP_PUSH2_ADR) / 4) + 2;
322 cell_t addr = ctx->frm + *cip++;
335 if (op >= OP_PUSH2_S)
336 n = ((op - OP_PUSH2_S) / 4) + 2;
340 cell_t value = Read(plugin, ctx->frm + *cip++);
354 n = ((op - OP_PUSH2) / 4) + 2;
358 cell_t value = Read(plugin, *cip++);
387 ctx->frm = uintptr_t(stk) - uintptr_t(plugin->memory);
401 pri = unsigned(pri) >> unsigned(alt);
498 cell_t offset = *cip++;
499 Write(plugin, offset, Read(plugin, offset) + 1);
505 cell_t offset = *cip++;
506 cell_t value = Read(plugin, ctx->frm + offset);
507 Write(plugin, ctx->frm + offset, value + 1);
512 if (!CheckAddress(plugin, ctx, stk, pri))
514 Write(plugin, pri, Read(plugin, pri) + 1);
526 cell_t offset = *cip++;
527 Write(plugin, offset, Read(plugin, offset) - 1);
533 cell_t offset = *cip++;
534 cell_t value = Read(plugin, ctx->frm + offset);
535 Write(plugin, ctx->frm + offset, value - 1);
540 if (!CheckAddress(plugin, ctx, stk, pri))
542 Write(plugin, pri, Read(plugin, pri) - 1);
546 pri = Read(plugin, *cip++);
549 alt = Read(plugin, *cip++);
553 pri = Read(plugin, ctx->frm + *cip++);
556 alt = Read(plugin, ctx->frm + *cip++);
560 pri = Read(plugin, ctx->frm + *cip++);
561 alt = Read(plugin, ctx->frm + *cip++);
566 pri = Read(plugin, ctx->frm + *cip++);
567 pri = Read(plugin, pri);
573 alt = Read(plugin, ctx->frm + *cip++);
574 alt = Read(plugin, alt);
586 pri = ctx->frm + *cip++;
589 alt = ctx->frm + *cip++;
593 Write(plugin, *cip++, pri);
596 Write(plugin, *cip++, alt);
600 Write(plugin, ctx->frm + *cip++, pri);
603 Write(plugin, ctx->frm +*cip++, alt);
612 cell_t offset = *cip++;
613 cell_t addr = Read(plugin, ctx->frm + offset);
614 Write(plugin, addr, pri);
620 cell_t offset = *cip++;
621 cell_t addr = Read(plugin, ctx->frm + offset);
622 Write(plugin, addr, alt);
636 cell_t reg = (op == OP_SREF_S_PRI) ? pri : alt;
645 if (!CheckAddress(plugin, ctx, stk, pri))
647 pri = Read(plugin, pri);
653 pri = alt + (pri << val);
654 if (!CheckAddress(plugin, ctx, stk, pri))
656 pri = Read(plugin, pri);
662 cell_t offset = *cip++;
663 cell_t value = *cip++;
664 Write(plugin, offset, value);
670 cell_t offset = *cip++;
671 cell_t value = *cip++;
672 Write(plugin, ctx->frm + offset, value);
677 if (!CheckAddress(plugin, ctx, stk, pri))
679 pri = Read(plugin, pri);
683 if (!CheckAddress(plugin, ctx, stk, alt))
685 Write(plugin, alt, pri);
691 cell_t dividend = (op == OP_SDIV) ? pri : alt;
692 cell_t divisor = (op == OP_SDIV) ? alt : pri;
694 ctx->err = SP_ERROR_DIVIDE_BY_ZERO;
697 if (dividend == INT_MIN && divisor == -1) {
698 ctx->err = SP_ERROR_INTEGER_OVERFLOW;
701 pri = dividend / divisor;
702 alt = dividend % divisor;
709 if (!CheckAddress(plugin, ctx, stk, pri))
711 pri = Read(plugin, pri);
722 if (!CheckAddress(plugin, ctx, stk, alt))
725 *reinterpret_cast<int8_t *>(plugin->memory + alt) = pri;
727 *reinterpret_cast<int16_t *>(plugin->memory + alt) = pri;
729 *reinterpret_cast<int32_t *>(plugin->memory + alt) = pri;
739 ctx->err = SP_ERROR_NONE;
745 uint8_t *src = plugin->memory + pri;
746 uint8_t *dest = plugin->memory + alt;
747 memcpy(dest, src, *cip++);
753 uint8_t *dest = plugin->memory + alt;
754 memset(dest, pri, *cip++);
758 case OP_STRADJUST_PRI:
765 cell_t amount = *cip++;
766 if (!IsValidOffset(amount)) {
767 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
773 if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) {
774 ctx->err = SP_ERROR_STACKMIN;
778 if (uintptr_t(stk) < uintptr_t(plugin->memory + ctx->hp + STACK_MARGIN)) {
779 ctx->err = SP_ERROR_STACKLOW;
788 cell_t amount = *cip++;
794 if (uintptr_t(plugin->memory + ctx->hp) > uintptr_t(stk)) {
795 ctx->err = SP_ERROR_HEAPLOW;
799 if (uint32_t(ctx->hp) < plugin->data_size) {
800 ctx->err = SP_ERROR_HEAPMIN;
808 if ((cip = JumpTarget(plugin, ctx, cip, true)) == NULL)
813 if ((cip = JumpTarget(plugin, ctx, cip, pri == 0)) == NULL)
817 if ((cip = JumpTarget(plugin, ctx, cip, pri != 0)) == NULL)
822 if ((cip = JumpTarget(plugin, ctx, cip, pri == alt)) == NULL)
826 if ((cip = JumpTarget(plugin, ctx, cip, pri != alt)) == NULL)
830 if ((cip = JumpTarget(plugin, ctx, cip, pri < alt)) == NULL)
834 if ((cip = JumpTarget(plugin, ctx, cip, pri <= alt)) == NULL)
838 if ((cip = JumpTarget(plugin, ctx, cip, pri > alt)) == NULL)
842 if ((cip = JumpTarget(plugin, ctx, cip, pri >= alt)) == NULL)
846 case OP_TRACKER_PUSH_C:
848 cell_t amount = *cip++;
849 int error = PushTracker(ctx, amount * 4);
850 if (error != SP_ERROR_NONE) {
857 case OP_TRACKER_POP_SETHEAP:
859 int error = PopTrackerAndSetHeap(rt);
860 if (error != SP_ERROR_NONE) {
868 ctx->cip = uintptr_t(cip - 1) - uintptr_t(plugin->pcode);
873 cell_t value = *cip++;
874 if (uint32_t(pri) > uint32_t(value)) {
875 ctx->err = SP_ERROR_ARRAY_BOUNDS;
883 cell_t offset = *cip++;
885 if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) {
886 ctx->err = SP_ERROR_INSTRUCTION_PARAM;
890 if (ctx->rp >= SP_MAX_RETURN_STACK) {
891 ctx->err = SP_ERROR_STACKLOW;
896 uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode);
897 ctx->rstk_cips[ctx->rp++] = rcip;
899 ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
901 int err = Interpret(rt, offset, &pri);
903 stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
907 if (err != SP_ERROR_NONE)
916 if (!GenerateArray(rt, ctx, val, stk, op == OP_GENARRAY_Z))
919 stk += (val - 1) * 4;
926 uint32_t native_index = *cip++;
928 if (native_index >= plugin->num_natives) {
929 ctx->err = SP_ERROR_INSTRUCTION_PARAM;
934 if (op == OP_SYSREQ_N) {
939 ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
940 pri = NativeCallback(ctx, native_index, stk);
941 if (ctx->n_err != SP_ERROR_NONE) {
942 ctx->err = ctx->n_err;
946 if (op == OP_SYSREQ_N)
947 stk += num_params + 1;
953 cell_t offset = *cip++;
954 cell_t *table = reinterpret_cast<cell_t *>(plugin->pcode + offset + sizeof(cell_t));
956 size_t ncases = *table++;
957 cell_t target = *table++; // default case
959 for (size_t i = 0; i < ncases; i++) {
960 if (table[i * 2] == pri) {
961 target = table[i * 2 + 1];
966 if ((cip = Jump(plugin, ctx, target)) == NULL)
973 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
980 assert(orig_frm == ctx->frm);
981 ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);