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 GenerateArray(BaseRuntime *rt, sp_context_t *ctx, cell_t dims, cell_t *stk, bool autozero)
174 uint32_t size = *stk;
175 if (size == 0 || !ke::IsUint32MultiplySafe(size, 4)) {
176 ctx->err = SP_ERROR_ARRAY_TOO_BIG;
181 uint32_t bytes = size * 4;
184 if (uintptr_t(ctx->plugin->memory + ctx->hp) >= uintptr_t(stk)) {
185 ctx->err = SP_ERROR_HEAPLOW;
189 if ((ctx->err = PushTracker(ctx, bytes)) != SP_ERROR_NONE)
193 memset(ctx->plugin->memory + ctx->hp, 0, bytes);
198 if ((ctx->err = GenerateFullArray(rt, dims, stk, autozero)) != SP_ERROR_NONE)
205 Interpret(BaseRuntime *rt, uint32_t aCodeStart, cell_t *rval)
207 const sp_plugin_t *plugin = rt->plugin();
208 cell_t *code = reinterpret_cast<cell_t *>(plugin->pcode);
209 cell_t *codeend = reinterpret_cast<cell_t *>(plugin->pcode + plugin->pcode_size);
211 if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size)
212 return SP_ERROR_INVALID_INSTRUCTION;
214 sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
215 ctx->err = SP_ERROR_NONE;
217 // Save the original frm. BaseContext won't, and if we error, we won't hit
218 // the stack unwinding code.
219 cell_t orig_frm = ctx->frm;
223 cell_t *cip = code + (aCodeStart / 4);
224 cell_t *stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
227 if (cip >= codeend) {
228 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
233 SpewOpcode(plugin, reinterpret_cast<cell_t *>(plugin->pcode + aCodeStart), cip);
236 OPCODE op = (OPCODE)*cip++;
255 Write(plugin, *cip++, 0);
259 Write(plugin, *cip++, 0);
276 if (op >= OP_PUSH2_C)
277 n = ((op - OP_PUSH2_C) / 4) + 2;
293 if (op >= OP_PUSH2_ADR)
294 n = ((op - OP_PUSH2_ADR) / 4) + 2;
299 cell_t addr = ctx->frm + *cip++;
312 if (op >= OP_PUSH2_S)
313 n = ((op - OP_PUSH2_S) / 4) + 2;
317 cell_t value = Read(plugin, ctx->frm + *cip++);
331 n = ((op - OP_PUSH2) / 4) + 2;
335 cell_t value = Read(plugin, *cip++);
364 ctx->frm = uintptr_t(stk) - uintptr_t(plugin->memory);
378 pri = unsigned(pri) >> unsigned(alt);
475 cell_t offset = *cip++;
476 Write(plugin, offset, Read(plugin, offset) + 1);
482 cell_t offset = *cip++;
483 cell_t value = Read(plugin, ctx->frm + offset);
484 Write(plugin, ctx->frm + offset, value + 1);
489 if (!CheckAddress(plugin, ctx, stk, pri))
491 Write(plugin, pri, Read(plugin, pri) + 1);
503 cell_t offset = *cip++;
504 Write(plugin, offset, Read(plugin, offset) - 1);
510 cell_t offset = *cip++;
511 cell_t value = Read(plugin, ctx->frm + offset);
512 Write(plugin, ctx->frm + offset, value - 1);
517 if (!CheckAddress(plugin, ctx, stk, pri))
519 Write(plugin, pri, Read(plugin, pri) - 1);
523 pri = Read(plugin, *cip++);
526 alt = Read(plugin, *cip++);
530 pri = Read(plugin, ctx->frm + *cip++);
533 alt = Read(plugin, ctx->frm + *cip++);
537 pri = Read(plugin, ctx->frm + *cip++);
538 alt = Read(plugin, ctx->frm + *cip++);
543 pri = Read(plugin, ctx->frm + *cip++);
544 pri = Read(plugin, pri);
550 alt = Read(plugin, ctx->frm + *cip++);
551 alt = Read(plugin, alt);
563 pri = ctx->frm + *cip++;
566 alt = ctx->frm + *cip++;
570 Write(plugin, *cip++, pri);
573 Write(plugin, *cip++, alt);
577 Write(plugin, ctx->frm + *cip++, pri);
580 Write(plugin, ctx->frm +*cip++, alt);
589 cell_t offset = *cip++;
590 cell_t addr = Read(plugin, ctx->frm + offset);
591 Write(plugin, addr, pri);
597 cell_t offset = *cip++;
598 cell_t addr = Read(plugin, ctx->frm + offset);
599 Write(plugin, addr, alt);
613 cell_t reg = (op == OP_SREF_S_PRI) ? pri : alt;
622 if (!CheckAddress(plugin, ctx, stk, pri))
624 pri = Read(plugin, pri);
630 pri = alt + (pri << val);
631 if (!CheckAddress(plugin, ctx, stk, pri))
633 pri = Read(plugin, pri);
639 cell_t offset = *cip++;
640 cell_t value = *cip++;
641 Write(plugin, offset, value);
647 cell_t offset = *cip++;
648 cell_t value = *cip++;
649 Write(plugin, ctx->frm + offset, value);
654 if (!CheckAddress(plugin, ctx, stk, pri))
656 pri = Read(plugin, pri);
660 if (!CheckAddress(plugin, ctx, stk, alt))
662 Write(plugin, alt, pri);
668 cell_t dividend = (op == OP_SDIV) ? pri : alt;
669 cell_t divisor = (op == OP_SDIV) ? alt : pri;
671 ctx->err = SP_ERROR_DIVIDE_BY_ZERO;
674 if (dividend == INT_MIN && divisor == -1) {
675 ctx->err = SP_ERROR_INTEGER_OVERFLOW;
678 pri = dividend / divisor;
679 alt = dividend % divisor;
686 if (!CheckAddress(plugin, ctx, stk, pri))
688 pri = Read(plugin, pri);
699 if (!CheckAddress(plugin, ctx, stk, alt))
702 *reinterpret_cast<int8_t *>(plugin->memory + alt) = pri;
704 *reinterpret_cast<int16_t *>(plugin->memory + alt) = pri;
706 *reinterpret_cast<int32_t *>(plugin->memory + alt) = pri;
716 ctx->err = SP_ERROR_NONE;
722 uint8_t *src = plugin->memory + pri;
723 uint8_t *dest = plugin->memory + alt;
724 memcpy(dest, src, *cip++);
730 uint8_t *dest = plugin->memory + alt;
731 memset(dest, pri, *cip++);
735 case OP_STRADJUST_PRI:
742 cell_t amount = *cip++;
743 if (!IsValidOffset(amount)) {
744 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
750 if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) {
751 ctx->err = SP_ERROR_STACKMIN;
755 if (uintptr_t(stk) < uintptr_t(plugin->memory + ctx->hp + STACK_MARGIN)) {
756 ctx->err = SP_ERROR_STACKLOW;
765 cell_t amount = *cip++;
771 if (uintptr_t(plugin->memory + ctx->hp) > uintptr_t(stk)) {
772 ctx->err = SP_ERROR_HEAPLOW;
776 if (uint32_t(ctx->hp) < plugin->data_size) {
777 ctx->err = SP_ERROR_HEAPMIN;
785 if ((cip = JumpTarget(plugin, ctx, cip, true)) == NULL)
790 if ((cip = JumpTarget(plugin, ctx, cip, pri == 0)) == NULL)
794 if ((cip = JumpTarget(plugin, ctx, cip, pri != 0)) == NULL)
799 if ((cip = JumpTarget(plugin, ctx, cip, pri == alt)) == NULL)
803 if ((cip = JumpTarget(plugin, ctx, cip, pri != alt)) == NULL)
807 if ((cip = JumpTarget(plugin, ctx, cip, pri < alt)) == NULL)
811 if ((cip = JumpTarget(plugin, ctx, cip, pri <= alt)) == NULL)
815 if ((cip = JumpTarget(plugin, ctx, cip, pri > alt)) == NULL)
819 if ((cip = JumpTarget(plugin, ctx, cip, pri >= alt)) == NULL)
823 case OP_TRACKER_PUSH_C:
825 cell_t amount = *cip++;
826 int error = PushTracker(ctx, amount * 4);
827 if (error != SP_ERROR_NONE) {
834 case OP_TRACKER_POP_SETHEAP:
836 int error = PopTrackerAndSetHeap(rt);
837 if (error != SP_ERROR_NONE) {
845 ctx->cip = uintptr_t(cip - 1) - uintptr_t(plugin->pcode);
850 cell_t value = *cip++;
851 if (uint32_t(pri) > uint32_t(value)) {
852 ctx->err = SP_ERROR_ARRAY_BOUNDS;
860 cell_t offset = *cip++;
862 if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) {
863 ctx->err = SP_ERROR_INSTRUCTION_PARAM;
867 if (ctx->rp >= SP_MAX_RETURN_STACK) {
868 ctx->err = SP_ERROR_STACKLOW;
873 uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode);
874 ctx->rstk_cips[ctx->rp++] = rcip;
876 ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
878 int err = Interpret(rt, offset, &pri);
880 stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
884 if (err != SP_ERROR_NONE)
893 if (!GenerateArray(rt, ctx, val, stk, op == OP_GENARRAY_Z))
896 stk += (val - 1) * 4;
903 uint32_t native_index = *cip++;
905 if (native_index >= plugin->num_natives) {
906 ctx->err = SP_ERROR_INSTRUCTION_PARAM;
911 if (op == OP_SYSREQ_N) {
916 ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
917 pri = NativeCallback(ctx, native_index, stk);
918 if (ctx->n_err != SP_ERROR_NONE) {
919 ctx->err = ctx->n_err;
923 if (op == OP_SYSREQ_N)
924 stk += num_params + 1;
930 cell_t offset = *cip++;
931 cell_t *table = reinterpret_cast<cell_t *>(plugin->pcode + offset + sizeof(cell_t));
933 size_t ncases = *table++;
934 cell_t target = *table++; // default case
936 for (size_t i = 0; i < ncases; i++) {
937 if (table[i * 2] == pri) {
938 target = table[i * 2 + 1];
943 if ((cip = Jump(plugin, ctx, target)) == NULL)
950 ctx->err = SP_ERROR_INVALID_INSTRUCTION;
957 assert(orig_frm == ctx->frm);
958 ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);