Line data Source code
1 : /* 2 : * SPDX-License-Identifier: MPL-2.0 3 : * 4 : * This Source Code Form is subject to the terms of the Mozilla Public 5 : * License, v. 2.0. If a copy of the MPL was not distributed with this 6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 : * 8 : * Copyright 2024 MonetDB Foundation; 9 : * Copyright August 2008 - 2023 MonetDB B.V.; 10 : * Copyright 1997 - July 2008 CWI. 11 : */ 12 : 13 : /* 14 : * (author) M. L. Kersten 15 : * @node Stack Management, The MAL Optimizer, Garbage Collection, The MAL Interpreter 16 : * @+ MAL runtime stack 17 : * The runtime context of a MAL procedure is allocated on the runtime stack 18 : * of the corresponding interpreter. 19 : * Access to the elements in the stack are through index offsets, 20 : * determined during MAL procedure parsing. 21 : * 22 : * The scope administration for MAL procedures is 23 : * decoupled from their actual runtime behavior. This means we are 24 : * more relaxed on space allocation, because the size is determined 25 : * by the number of MAL procedure definitions instead of the runtime 26 : * calling behavior. (See mal_interpreter for details on value stack 27 : * management) 28 : * 29 : * The variable names and types are kept in the stack to ease debugging. 30 : * The underlying string value need not be garbage collected. 31 : * Runtime storage for variables are allocated on the stack of the 32 : * interpreter thread. The physical stack is often limited in size, 33 : * which calls for safeguarding their value and garbage collection before returning. 34 : * A malicious procedure or implementation will lead to memory leakage. 35 : * 36 : * A system command (linked C-routine) may be interested in extending the 37 : * stack. This is precluded, because it could interfere with the recursive 38 : * calling sequence of procedures. To accommodate the (rare) case, the routine 39 : * should issue an exception to be handled by the interpreter before retrying. 40 : * All other errors are turned into an exception, followed by continuing 41 : * at the exception handling block of the MAL procedure. 42 : * 43 : * The interpreter should be protected against physical stack overflow. 44 : * The solution chosen is to maintain an incremental depth size. 45 : * Once it exceeds a threshold, we call upon the kernel to 46 : * ensure we are still within safe bounds. 47 : */ 48 : #include "monetdb_config.h" 49 : #include "mal_stack.h" 50 : #include "mal_exception.h" 51 : 52 : /* #define DEBUG_MAL_STACK*/ 53 : 54 : MalStkPtr 55 710125 : newGlobalStack(int size) 56 : { 57 710125 : MalStkPtr s; 58 : 59 710125 : s = (MalStkPtr) GDKzalloc(stackSize(size)); 60 710236 : if (!s) 61 : return NULL; 62 710236 : s->stksize = size; 63 710236 : return s; 64 : } 65 : 66 : MalStkPtr 67 4 : reallocGlobalStack(MalStkPtr old, int cnt) 68 : { 69 4 : int k; 70 4 : MalStkPtr s; 71 : 72 4 : if (old->stksize > cnt) 73 : return old; 74 4 : k = ((cnt / STACKINCR) + 1) * STACKINCR; 75 4 : s = newGlobalStack(k); 76 4 : if (!s) { 77 : return NULL; 78 : } 79 4 : memcpy(s, old, stackSize(old->stksize)); 80 4 : s->stksize = k; 81 4 : GDKfree(old); 82 4 : return s; 83 : } 84 : 85 : /* 86 : * The clearStack operation throws away any space occupied by variables 87 : * Freeing the stack itself is automatic upon return from the interpreter 88 : * context. Since the stack is allocated and zeroed on the calling stack, 89 : * it may happen that entries are never set to a real value. 90 : * This can be recognized by the vtype component 91 : */ 92 : static void 93 635585 : clearStack(MalStkPtr s) 94 : { 95 635585 : ValPtr v; 96 635585 : int i; 97 : 98 635585 : if (!s) 99 : return; 100 : 101 635585 : i = s->stktop; 102 67567211 : for (v = s->stk; i > 0; i--, v++) 103 66931533 : if (v->bat) { 104 1043709 : BBPrelease(v->val.bval); 105 1043315 : v->bat = false; 106 65887824 : } else if (ATOMextern(v->vtype) && v->val.pval) { 107 556083 : GDKfree(v->val.pval); 108 556570 : v->vtype = 0; 109 556570 : v->val.pval = NULL; 110 : } 111 635678 : s->stkbot = 0; 112 : } 113 : 114 : /* 115 : * When you add a value to the stack, you should ensure that 116 : * there is space left. It should only be used for global 117 : * stack frames, because the others are allocated in the 118 : * runtime stack. 119 : */ 120 : void 121 635579 : freeStack(MalStkPtr stk) 122 : { 123 635579 : if (stk != NULL) { 124 635579 : clearStack(stk); 125 635682 : GDKfree(stk); 126 : } 127 635693 : }