Skip site navigation (1)Skip section navigation (2)
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>