=============================================================================== Fixes for the Small compiler and virtual machine =============================================================================== By James Haley ======== Updates ======== 08/02/03 -- Added Marc Peter's fix for a missing field in the JIT's amx structure Although I have made every attempt to ensure that the code in these patches is safe and correct, I make NO WARRANTIES, express or implied, to that effect, or regarding the fitness of this code for any purpose. By using this code you agree to release me from any damages that might result from its use. I release these changes into the public domain so that they can be used freely in accordance to the same terms under which the Small compiler and virtual machine are released. DIFF notation: Lines beginning with a + are lines to add. Lines beginning with a - are lines to take away. Lines beginning with space remain unchanged. ========= VM Fixes ========= I have identified two problems with the VM (or AMX) source code. The first is a simple issue with the amx.h include file which causes a number of spurious warnings when compiling under some GNU compilers. NOTE: if compiled under C++, this fix may need a different approach, since GNU C doesn't support this syntax for __attribute__ under C++. I have not tested it under C++, however. ======================================= Structure Alignment fix for GCC, amx.h ======================================= Near line 39: + /* haleyjd 03/16/03: GCC does not support #pragma pack, and is going + * crazy over its + * use here. So to that end, I've added __GNUC__ here, and defined + * __attribute__ instead. + */ - #if defined SN_TARGET_PS2 + #if defined SN_TARGET_PS2 || defined __GNUC__ #define AMX_NO_ALIGN #endif + #ifndef __GNUC__ + #define __attribute__(x) + #endif Near line 104: typedef struct { char FAR *name; AMX_NATIVE func; - } AMX_NATIVE_INFO; + } __attribute__((packed)) AMX_NATIVE_INFO; ... typedef struct { uint32_t address; char name[sEXPMAX+1]; - } AMX_FUNCSTUB; + } __attribute__((packed)) AMX_FUNCSTUB; Near line 153: long code_size; /* estimated memory footprint of the native code */ #endif - } AMX; + } __attribute__((packed)) AMX; Near line 176: int32_t pubvars; /* the "public variables" table */ int32_t tags; /* the "public tagnames" table */ - } AMX_HEADER; + } __attribute__((packed)) AMX_HEADER; #define AMX_MAGIC 0xf1e0 ============================================ Array bounds checking off by one fix, amx.c ============================================ This fixes the second issue identified in the VM, a security hazard that allows access to array indices one past the actual end of the array. This is due to a very simple operator error in the OP_BOUNDS opcode. Fix in amx.c function amx_Exec (GNU C version), near line 1977: op_bounds: GETPARAM(offs); + /* haleyjd 07/18/03: SMALL FIX -- check was > when it should have + * been >=; this allowed array access one past the end + */ - if (pri>offs || pri<0) + if (pri>=offs || pri<0) ABORT(amx,AMX_ERR_BOUNDS); NEXT(cip); Fix in amx.c function amx_Exec (ANSI C version), near line 2930: case OP_BOUNDS: GETPARAM(offs); + /* haleyjd 07/18/03: SMALL FIX -- check was > when it should have + * been >=; this allowed array access one past the end + */ - if (pri>offs || pri<0) + if (pri>=offs || pri<0) ABORT(amx,AMX_ERR_BOUNDS); break; ========== JIT Fixes ========== Thanks to Marc Peter for contributing these fixes to the Just-In-Time compiler. ======================================================== Missing amx structure fields in JIT: jits.asm, jitr.asm ======================================================== jits.asm, line 134: _hea DD ? + _hlw DD ? ; <- was missing before _stk DD ? jitr.asm, line 130: _hea DD ? + _hlw DD ? ; <- was missing before _stk DD ? =============== Compiler Fixes =============== I have so far repaired three issues with the Small compiler: * for loop label deletion * segv on value return conflict * segv on missing brace error =================================== For loop label deletion fix, sc1.c =================================== For loops which declare a variable in the initialization statement, as in the following example, delete labels declared inside them. If the label is then referenced outside of the loop, the compiler will complain that it is an undeclared symbol. Example: for(new i = 0; i < 3; i++) { some_label: ... } goto some_label; Fix in sc1.c function "dofor", near line 3349: modstk((int)(declared-save_decl)*sizeof(cell)); declared=save_decl; + /* haleyjd 07/18/03: labels should NOT be deleted here */ - delete_symbols(&loctab,nestlevel,TRUE,TRUE); + delete_symbols(&loctab,nestlevel,FALSE,TRUE); ====================================================== SEGV when functions both do and do not return a value ====================================================== Functions like the following can cause a SEGV or assertion failure: a() { if(foo) return; return 0; } Fix in sc1.c function "doreturn", near line 3616: assert(curfunc!=NULL); funcdisplayname(symname,curfunc->name); + /* haleyjd 07/18/03: SMALL FIX: this error was missing the + * symbol name parameter (causes segv in std compiler) + */ - error(209); /* function should return a value */ + error(209, symname); /* function should return a value */ ============================================== SEGV on missing brace syntax error fix, sc5.c ============================================== Due to the complicated nature of this error, the best way in which I was able to fix it was to make error 54 fatal. It is highly unlikely that the parser would ever be able to meaningfully recover from a missing brace error anyways, so this makes sense in my mind. A more appropriate fix would be to actually make the parser safer, so that it does not crash on any syntax error. That is a very tall order, however. It would also be more appropriate to change the error number 54 to 154, to automatically promote it to a fatal error without a special case. However, I have not done this in order to minimize the impact of the change on other code, so that if Thiadmer later fixes this himself, this temporary fix can be easily removed. Fix in sc5.c, function error, near line 54: + /* haleyjd 07/18/03: special case some errors to prevent compiler + * crashes -- best I can do without a full understanding of + * Thiadmer's code. + */ + /* error 54, causes assertion failure at file sc4.c, line 51 */ + if(number == 54){ + msg=errmsg[number-1]; /* leaving message alone, but making fatal */ + pre=prefix[1]; + errnum++; - if(number<100){ + } else if (number<100){ msg=errmsg[number-1]; pre=prefix[0]; Fix in sc5.c, function error, near line 102: + /* haleyjd 07/18/03: added special case for 54 */ - if (number>=100 && number<200 || errnum>25){ + if (number>=100 && number<200 || errnum>25 || number == 54){ if (strlen(errfname)==0) { va_start(argptr,number); =============================================================================== EOF ===============================================================================