Date: Tue, 12 Jan 1999 03:26:15 +0900 (JST) From: dcs@newsguy.com To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: kern/9442: ficl's evaluate is out of spec Message-ID: <199901111826.DAA00878@daniel.sobral>
next in thread | raw e-mail | index | archive | help
>Number: 9442 >Category: kern >Synopsis: ficl's evaluate ignores the count passed to it >Confidential: no >Severity: serious >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Jan 11 10:30:00 PST 1999 >Closed-Date: >Last-Modified: >Originator: Daniel C. Sobral >Release: FreeBSD 3.0-CURRENT i386 >Organization: >Environment: Three stage boot's loader. >Description: FICL, used by loader, ignores the count passed to it by EVALUATE. This is completely out of spec with ANS Forth standard. As a result, we can expect breakage in ANS Forth standard programs and library, and violate POLA for Forth programmers. >How-To-Repeat: Boot loader. Enter: : s s" 1 2 3" ; s drop 1 evaluate .s (other "examples" may cause page faults) >Fix: Change structure TIB to indicate the size of buffer. This has been done by adding a "end" pointer instead of the size itself. #TIB is obsolete, so we don't need to implement it, and because of the way ficl works (by respecting null-terminated strings), having a pointer makes the extra tests faster. Old funcionality, unknown size buffers, can be obtained by setting the size to -1 (ficlExec and vmPushTib take the buffers size, not the pointer). Change all words doing TIB scanning to respect this limit. Change sys/boot/common/interp_forth.c to respect this limit too. Change EVALUATE to pass the buffer size to ficlExec instead of ignoring. Change testmain.c to keep it compilable. There are two places in these diffs that depend on previous PRs, though. Besides the diff to softcore.pl, a diff for softcore.sh is also provided, in case the PR replacing the perl script with a C program gets accepted. Also, testmain includes a patch that corrects the working of it's "load" command EXCEPTION word set PR. If that PR is not brought in, the line "if (result >= VM_ERREXIT)" must not be changed (it is replaced by a line testing against, among others, VM_ABORT and VM_ABORTQ, not present without the EXCEPTION word set PR, though otherwise the changes are still correct, if unneeded). So, apply the following patches: --- sys/boot/ficl/testmain.c 1999/01/11 17:57:30 1.2 +++ sys/boot/ficl/testmain.c 1999/01/11 17:57:57 1.3 @@ -144,11 +144,8 @@ if (len <= 0) continue; - if (cp[len] == '\n') - cp[len] = '\0'; - - result = ficlExec(pVM, cp); - if (result >= VM_ERREXIT) + result = ficlExec(pVM, cp, len); + if (result != VM_QUIT && result != VM_USEREXIT && result != VM_OUTOFTEXT ) { pVM->sourceID = id; fclose(fp); @@ -161,7 +158,7 @@ ** any pending REFILLs (as required by FILE wordset) */ pVM->sourceID.i = -1; - ficlExec(pVM, ""); + ficlExec(pVM, "", 0); pVM->sourceID = id; fclose(fp); @@ -246,7 +243,7 @@ buildTestInterface(); pVM = ficlNewVM(); - ficlExec(pVM, ".ver .( " __DATE__ " ) cr quit"); + ficlExec(pVM, ".ver .( " __DATE__ " ) cr quit", -1); /* ** load file from cmd line... @@ -254,7 +251,7 @@ if (argc > 1) { sprintf(in, ".( loading %s ) cr load %s\n cr", argv[1], argv[1]); - ficlExec(pVM, in); + ficlExec(pVM, in, -1); } for (;;) @@ -262,7 +259,7 @@ int ret; if (fgets(in, sizeof(in) - 1, stdin) == NULL) break; - ret = ficlExec(pVM, in); + ret = ficlExec(pVM, in, -1); if (ret == VM_USEREXIT) { ficlTermSystem(); --- sys/boot/ficl/ficl.h 1999/01/10 02:37:36 1.2 +++ sys/boot/ficl/ficl.h 1999/01/11 17:31:24 @@ -166,6 +166,12 @@ /* ** Revision History: +** +** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an +** "end" field, and all words respect this. ficlExec is passed a "size" +** of TIB, as well as vmPushTib. This size is used to calculate the "end" +** of the string, ie, base+size. If the size is not known, pass -1. +** ** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing ** words has been modified to conform to EXCEPTION EXT word set. ** @@ -308,10 +314,19 @@ ** the block of text it's working on and an index to the next ** unconsumed character in the string. Traditionally, this is ** done by a Text Input Buffer, so I've called this struct TIB. +** +** Since this structure also holds the size of the input buffer, +** and since evaluate requires that, let's put the size here. +** The size is stored as an end-pointer because that is what the +** null-terminated string aware functions find most easy to deal +** with. +** Notice, though, that nobody really uses this except evaluate, +** so it might just be moved to FICL_VM instead. (sobral) */ typedef struct { INT32 index; + char *end; char *cp; } TIB; @@ -531,7 +546,7 @@ ** PopTib restores the TIB state given a saved TIB from PushTib ** GetInBuf returns a pointer to the next unused char of the TIB */ -void vmPushTib(FICL_VM *pVM, char *text, TIB *pSaveTib); +void vmPushTib(FICL_VM *pVM, char *text, INT32 size, TIB *pSaveTib); void vmPopTib(FICL_VM *pVM, TIB *pTib); #define vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index) #define vmSetTibIndex(pVM, i) (pVM)->tib.index = i @@ -553,7 +568,7 @@ char *ultoa(UNS32 value, char *string, int radix ); char digit_to_char(int value); char *strrev( char *string ); -char *skipSpace(char *cp); +char *skipSpace(char *cp,char *end); char *caseFold(char *cp); int strincmp(char *cp1, char *cp2, FICL_COUNT count); @@ -695,7 +710,8 @@ ** f i c l E x e c ** Evaluates a block of input text in the context of the ** specified interpreter. Emits any requested output to the -** interpreter's output function +** interpreter's output function. If the size of the input +** is not known, pass -1. ** Execution returns when the text block has been executed, ** or an error occurs. ** Returns one of the VM_XXXX codes defined in ficl.h: @@ -707,10 +723,12 @@ ** to shut down the interpreter. This would be a good ** time to delete the vm, etc -- or you can ignore this ** signal. +** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"' +** commands. ** Preconditions: successful execution of ficlInitSystem, ** Successful creation and init of the VM by ficlNewVM (or equiv) */ -int ficlExec(FICL_VM *pVM, char *pText); +int ficlExec(FICL_VM *pVM, char *pText, INT32 size); /* ** ficlExecFD(FICL_VM *pVM, int fd); --- sys/boot/ficl/ficl.c 1999/01/10 01:59:37 1.1 +++ sys/boot/ficl/ficl.c 1999/01/11 17:28:39 @@ -170,7 +170,7 @@ ** time to delete the vm, etc -- or you can ignore this ** signal. **************************************************************************/ -int ficlExec(FICL_VM *pVM, char *pText) +int ficlExec(FICL_VM *pVM, char *pText, INT32 size) { int except; FICL_WORD *tempFW; @@ -180,7 +180,7 @@ assert(pVM); - vmPushTib(pVM, pText, &saveTib); + vmPushTib(pVM, pText, size, &saveTib); /* ** Save and restore VM's jmp_buf to enable nested calls to ficlExec @@ -287,8 +287,7 @@ break; continue; } - cp[i] = '\0'; - if ((rval = ficlExec(pVM, cp)) >= VM_ERREXIT) + if ((rval = ficlExec(pVM, cp, i)) >= VM_ERREXIT) { pVM->sourceID = id; vmThrowErr(pVM, "ficlExecFD: Error at line %d", nLine); @@ -300,7 +299,7 @@ ** any pending REFILLs (as required by FILE wordset) */ pVM->sourceID.i = -1; - ficlExec(pVM, ""); + ficlExec(pVM, "", 0); pVM->sourceID = id; return rval; --- sys/boot/ficl/words.c 1999/01/10 01:59:16 1.3 +++ sys/boot/ficl/words.c 1999/01/11 16:39:46 @@ -880,7 +880,7 @@ char *cp = vmGetInBuf(pVM); char ch = *cp; - while ((ch != '\0') && (ch != '\r') && (ch != '\n')) + while ((pVM->tib.end != cp) && (ch != '\0') && (ch != '\r') && (ch != '\n')) { ch = *++cp; } @@ -890,11 +890,11 @@ ** Check for /r, /n, /r/n, or /n/r end-of-line sequences, ** and point cp to next char. If EOL is \0, we're done. */ - if (ch != '\0') + if ((pVM->tib.end != cp) && (ch != '\0')) { cp++; - if ( (ch != *cp) + if ( (pVM->tib.end != cp) && (ch != *cp) && ((*cp == '\r') || (*cp == '\n')) ) cp++; } @@ -2065,13 +2065,13 @@ char *pDest = pVM->pad; char ch; - pSrc = skipSpace(pSrc); + pSrc = skipSpace(pSrc,pVM->tib.end); - for (ch = *pSrc; (ch != '\0') && (ch != ')'); ch = *++pSrc) + for (ch = *pSrc; (pVM->tib.end != pSrc) && (ch != '\0') && (ch != ')'); ch = *++pSrc) *pDest++ = ch; *pDest = '\0'; - if (ch == ')') + if ((pVM->tib.end != pSrc) && (ch == ')')) pSrc++; vmTextOut(pVM, pVM->pad, 0); @@ -2458,6 +2458,10 @@ ** Implementation: if there's more text in the TIB, use it. Otherwise ** throw out for more text. Copy characters up to the max count into the ** address given, and return the number of actual characters copied. +** +** This may not strictly violate the standard, but I'm sure any programs +** asking for user input at load time will *not* be expecting this +** behavior. (sobral) **************************************************************************/ static void accept(FICL_VM *pVM) { @@ -2465,7 +2469,7 @@ char *cp; char *pBuf = vmGetInBuf(pVM); - len = strlen(pBuf); + for (len = 0; pVM->tib.end != &pBuf[len] && pBuf[len]; len++); if (len == 0) vmThrow(pVM, VM_RESTART); /* OK - now we have something in the text buffer - use it */ @@ -2688,7 +2692,7 @@ ** EVALUATE CORE ( i*x c-addr u -- j*x ) ** Save the current input source specification. Store minus-one (-1) in ** SOURCE-ID if it is present. Make the string described by c-addr and u -** both the input source and input buffer, set >IN to zero, and interpret. +** both the input source andinput buffer, set >IN to zero, and interpret. ** When the parse area is empty, restore the prior input source ** specification. Other stack effects are due to the words EVALUATEd. ** @@ -2697,16 +2701,15 @@ **************************************************************************/ static void evaluate(FICL_VM *pVM) { - UNS32 count = stackPopUNS32(pVM->pStack); + INT32 count = stackPopINT32(pVM->pStack); char *cp = stackPopPtr(pVM->pStack); CELL id; int result; - IGNORE(count); id = pVM->sourceID; pVM->sourceID.i = -1; vmPushIP(pVM, &pInterpret); - result = ficlExec(pVM, cp); + result = ficlExec(pVM, cp, count); vmPopIP(pVM); pVM->sourceID = id; if (result != VM_OUTOFTEXT) @@ -2840,12 +2843,12 @@ cp = pSrc; /* mark start of text */ - while ((*pSrc != delim) && (*pSrc != '\0')) + while ((pVM->tib.end != pSrc) && (*pSrc != delim) && (*pSrc != '\0')) pSrc++; /* find next delimiter or end */ count = pSrc - cp; /* set length of result */ - if (*pSrc == delim) /* gobble trailing delimiter */ + if ((pVM->tib.end != pSrc) && (*pSrc == delim)) /* gobble trailing delimiter */ pSrc++; vmUpdateTib(pVM, pSrc); @@ -3156,9 +3159,11 @@ ** input buffer. **************************************************************************/ static void source(FICL_VM *pVM) -{ +{ int i; + stackPushPtr(pVM->pStack, pVM->tib.cp); - stackPushINT32(pVM->pStack, strlen(pVM->tib.cp)); + for (i = 0; (pVM->tib.end != &pVM->tib.cp[i]) && pVM->tib.cp[i]; i++); + stackPushINT32(pVM->pStack, i); return; } --- sys/boot/ficl/vm.c 1999/01/11 17:56:10 1.2 +++ sys/boot/ficl/vm.c 1999/01/11 17:57:09 @@ -156,17 +156,17 @@ UNS32 count = 0; char ch; - pSrc = skipSpace(pSrc); + pSrc = skipSpace(pSrc,pVM->tib.end); SI_SETPTR(si, pSrc); - for (ch = *pSrc; ch != '\0' && !isspace(ch); ch = *++pSrc) + for (ch = *pSrc; (pVM->tib.end != pSrc) && (ch != '\0') && !isspace(ch); ch = *++pSrc) { count++; } SI_SETLEN(si, count); - if (isspace(ch)) /* skip one trailing delimiter */ + if ((pVM->tib.end != pSrc) && isspace(ch)) /* skip one trailing delimiter */ pSrc++; vmUpdateTib(pVM, pSrc); @@ -210,14 +210,15 @@ { STRINGINFO si; char *pSrc = vmGetInBuf(pVM); - char ch; + char ch; - while (*pSrc == delim) /* skip lead delimiters */ + while ((pVM->tib.end != pSrc) && (*pSrc == delim)) /* skip lead delimiters */ pSrc++; SI_SETPTR(si, pSrc); /* mark start of text */ - for (ch = *pSrc; (ch != delim) + for (ch = *pSrc; (pVM->tib.end != pSrc) + && (ch != delim) && (ch != '\0') && (ch != '\r') && (ch != '\n'); ch = *++pSrc) @@ -228,7 +229,7 @@ /* set length of result */ SI_SETLEN(si, pSrc - SI_PTR(si)); - if (*pSrc == delim) /* gobble trailing delimiter */ + if ((pVM->tib.end != pSrc) && (*pSrc == delim)) /* gobble trailing delimiter */ pSrc++; vmUpdateTib(pVM, pSrc); @@ -263,7 +264,7 @@ v m P u s h T i b ** Binds the specified input string to the VM and clears >IN (the index) **************************************************************************/ -void vmPushTib(FICL_VM *pVM, char *text, TIB *pSaveTib) +void vmPushTib(FICL_VM *pVM, char *text, INT32 size, TIB *pSaveTib) { if (pSaveTib) { @@ -271,6 +272,7 @@ } pVM->tib.cp = text; + pVM->tib.end = text + size; pVM->tib.index = 0; } @@ -302,6 +304,7 @@ pVM->runningWord = pInterp; pVM->state = INTERPRET; pVM->tib.cp = NULL; + pVM->tib.end = NULL; pVM->tib.index = 0; pVM->pad[0] = '\0'; pVM->sourceID.i = 0; @@ -551,12 +554,14 @@ s k i p S p a c e ** Given a string pointer, returns a pointer to the first non-space ** char of the string, or to the NULL terminator if no such char found. +** If the pointer reaches "end" first, stop there. If you don't want +** that, pass NULL. **************************************************************************/ -char *skipSpace(char *cp) +char *skipSpace(char *cp, char *end) { assert(cp); - while (isspace(*cp)) + while ((cp != end) && isspace(*cp)) cp++; return cp; --- sys/boot/ficl/softwords/softcore.sh 1999/01/09 22:01:26 1.1 +++ sys/boot/ficl/softwords/softcore.sh 1999/01/11 16:36:17 @@ -30,7 +30,7 @@ void ficlCompileSoftCore(FICL_VM *pVM) { - assert(ficlExec(pVM, softWords) != VM_ERREXIT); + assert(ficlExec(pVM, softWords, -1) != VM_ERREXIT); } --- sys/boot/ficl/softwords/softcore.pl 1999/01/11 17:54:12 1.2 +++ sys/boot/ficl/softwords/softcore.pl 1999/01/11 17:54:46 @@ -77,7 +77,7 @@ void ficlCompileSoftCore(FICL_VM *pVM) { - assert(ficlExec(pVM, softWords) != VM_ERREXIT); + assert(ficlExec(pVM, softWords, -1) != VM_ERREXIT); } --- sys/boot/common/interp_forth.c 1999/01/10 02:40:11 1.4 +++ sys/boot/common/interp_forth.c 1999/01/11 17:31:57 @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: interp_forth.c,v 1.4 1999/01/10 02:40:11 root Exp $ + * $Id: interp_forth.c,v 1.5 1999/01/11 17:31:47 root Exp root $ */ #include <string.h> @@ -80,7 +80,7 @@ /* Get remainder of invocation */ tail = vmGetInBuf(vm); - for (cp = tail, len = 0; *cp != 0 && *cp != '\n'; cp++, len++) + for (cp = tail, len = 0; cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++) ; line = malloc(strlen(name) + len + 2); @@ -129,13 +129,13 @@ bf_vm = ficlNewVM(); /* Builtin word "creator" */ - ficlExec(bf_vm, ": builtin: >in @ ' swap >in ! create , does> @ execute throw ;"); + ficlExec(bf_vm, ": builtin: >in @ ' swap >in ! create , does> @ execute throw ;", -1); /* make all commands appear as Forth words */ SET_FOREACH(cmdp, Xcommand_set) { ficlBuild((*cmdp)->c_name, bf_command, FW_DEFAULT); sprintf(create_buf, "builtin: %s", (*cmdp)->c_name); - ficlExec(bf_vm, create_buf); + ficlExec(bf_vm, create_buf, -1); } /* try to load and run init file if present */ @@ -153,7 +153,7 @@ { int result; - result = ficlExec(bf_vm, line); + result = ficlExec(bf_vm, line, -1); DEBUG("ficlExec '%s' = %d", line, result); switch (result) { case VM_OUTOFTEXT: >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199901111826.DAA00878>