Nombas Homepage

Scripting

Products

Purchase

Download

Support

Company

Nombas > SE:ISDK DevSpace > Errata > Integration SDK 5.01x Errata

 

Integration SDK 5.01x Errata
Fixes Affecting Users of the ScriptEase ISDKs

  • 5.01b API - latest update: December 8, 2004

API Errata, version 5.01b
  New, December 2, 2004

API Errata, version 5.01a
  New, March 18, 2004

The Details

for 5.01b -- (may apply to earlier version)

  • Clib method configuration compiler error
    (for ISDK/C 5.01b)

Bug: When the JSE_CLIB_ALL flag is turned off in a jseopt.h file, and just the JSE_CLIB_SPRINTF, JSE_CLIB_RSPRINTF, and JSE_CLIB_SSCANF flags are turned on, the compiler complains that vsscanf_sechar is undefined.

Fix n src/lib/clib/sestdio.c, near line 1075, there is a comment an an #if statement that looks like this:


   /* Disgusting kludge to get a vscanf-type function on platforms that don't support it */
   #if defined(JSE_CLIB_FSCANF) || \
       defined(JSE_CLIB_VFSCANF) || \
       defined(JSE_CLIB_SCANF) || \
       defined(JSE_CLIB_VSCANF)
Add line to that #if statement, so that it looks like this:

   /* Disgusting kludge to get a vscanf-type function on platforms that don't support it */
   #if defined(JSE_CLIB_FSCANF) || \
       defined(JSE_CLIB_VFSCANF) || \
       defined(JSE_CLIB_SCANF) || \
       defined(JSE_CLIB_VSCANF) || \
       defined(JSE_CLIB_SSCANF)
Then, in src/lib/clib/sefile.h, around line 59, there is a #define statement that looks like this:

   # define DEFAULT_FGETS_BUFSIZE 1000 /* used if none supplied */
Just above that #define statement, there is a large #if statement. Add a line to the end of it so that instead of having the last few lines look like this:

   ...
   || defined(JSE_CLIB_GETCHAR) \
   || defined(JSE_CLIB_PUTCHAR) \
   || defined(JSE_CLIB_PERROR) \
   || defined(JSE_CLIB_PUTS)
...it should look like this:

   ...
   || defined(JSE_CLIB_GETCHAR) \
   || defined(JSE_CLIB_PUTCHAR) \
   || defined(JSE_CLIB_PERROR) \
   || defined(JSE_CLIB_PUTS) \
   || defined(JSE_CLIB_SSCANF)

  • seLockString() returns garbage
    (for ISDK/C 5.01b)

Bug: seLockString() does not return a valid string value.

Fix Around line 787, change this line:

   struct seapiLockItem *str = (struct seapiLockItem *)data;

to this:

   struct seapiLockItem *str = find_seTempLockString(call,data);

  • seEval() does not follow correct function scoping rules when executing a function literal object
    (for ISDK/C 5.01b)

Bug: When calling a function literal, that function is supposed to remember the values of the variables it had access to at the time of its creation. This works in ScriptEase as long as the funciton literal is being called from within a script. However, before applying this erratum, this won't work in ScriptEase when calling the function literal from a wrapper function using seEval().

Fix Replace se501/src/core/analyze.c, se501/src/core/call.h, se501/src/core/garbage.c, and se501/src/core/se501.c with the ones found in this zip file: scope.tar.gz

  • Dynamic get callback is not receiving call_hint when applied to the global variable
    (for ISDK/C 5.01b)

Bug: If the global variable has a get() callback assigned through seSetCallbacks, then the get callback may not be receiving the call_hint variable set as True when a property is retrieved as a method (e.g. global.foo(), or just foo()).

Fix : In se501/src/core/varutil.c, function seobjHasProperty(), at around line 2733 change this statement:

   if( seobjCallDynamicProperty(call,hobj,SE_GET_CALLBACK,propname,False,rhs) )

to this statement:

   if( seobjCallDynamicProperty(call,hobj,SE_GET_CALLBACK,propname,
         (rSEVar)( NULL != FUNCPTR
                && FUNCTION_IS_LOCAL(FUNCPTR)
                && ( (seThisAndValue == IPTR[0] && ( seToCallFunc==IPTR[1]
                                                  || seToNewFunc==IPTR[1]))
                  || seToNewFunc==IPTR[0] ) ),
         rhs) )

  • The Math constants (Math.PI, Math.LOG2E, ect) are defined as strings, not numbers
    (for ISDK/C 5.01b)

Bug: The Math constants (Math.PI, Math.E, Math.LN10, Math.LN2, Math.LOG2E, Math.LOG10E, Math.SQRT1_2, Math.SQRT2) are incorrectly defined as strings, not numbers. For most math operations, that is acceptable (although ineffecient) because the string values are converted to numbers. But addition fails, because any addition involving strings turns into a concatenation operation. That means 5 + Math.PI results in the string "53.14159265358979323846".

Fix : In se501/src/lib/ecma/mathobj.c locate the Math library table, identified by SE_BEGIN_LIB_TABLE, around line 1751. In the library table, each of the Math constants listed above is declared with the SE_STRING() macro. Change each Math constant entry to use the SE_NUMLITERAL() macro. This is what the Math.E entry looks like after applying the fix:

     SE_NUMLITERAL(UNISTR("E"),        E_VALUE,        SE_DONTENUM|SE_DONTDELETE|SE_READONLY)

Also, in se501/src/core/se501.c, function seAddLibTable() around line 6224, add a 'break' statement at the end of the 'case SE_NUMLITERAL_TYPE:' block. The block should look like this after applying the fix:

     case SE_NUMLITERAL_TYPE:
        SEVAR_COPY(tmp,place);
        str_name = PALMTABLE_STR_DEREF(table->name);
        GetDotNamedVar(call,tmp,str_name,SE_DEFAULT);
        str_value = PALMTABLE_STR_DEREF(table->value);
        SEVAR_INIT_NUMBER(tmp2,convertStringToNumber(call,str_value,strlen_sechar(str_value)));
        /* We must turn off flags for this variable so put succeeds */
        SEASSERT( SEVAR_GET_TYPE(tmp)==VReference );
        seobjSetAttributes(call,tmp->data.ref_val.hBase,
                           tmp->data.ref_val.reference,0);
        SEVAR_DO_PUT(call,tmp,tmp2);
        /* Now restore flags with the user-supplied var attribs */
        seobjSetAttributes(call,tmp->data.ref_val.hBase,
                           tmp->data.ref_val.reference,
                           table->varFlags);

        break;             

  • comobj library passing wrong Boolean values to COM object functions
    (for ISDK/C 5.01b)

Bug: When calling a method of a COM object, the comobj library passes its native values for True and False, which are 1 and 0, respectively. This can cause Visual Basic 6 methods to behave strangely, for instance interpreting the value as Boolean True, but then interpreting the logical Not value of the argument as also being True.

Fix : In se501/src/lib/comobj/comobj.cpp, in the function convertFromJSBoolean(), around line 1855, there is the VT_BOOL case statement. Change the code in that statement from this:

      V_VT(varg) = (VARTYPE)(VT_BOOL | byRefModifier);
      if ( byRefModifier != 0 )
      {
         short * temp = comobjMustMalloc(short,sizeof(*temp));
         *temp = JSVal;
         V_BOOLREF(varg) = temp;
      }
      else
      {
         V_BOOL(varg) = JSVal;
      }
      break;

to this:

      short result;
      hr = VarBoolFromR8(JSVal, &result);
      V_VT(varg) = (VARTYPE)(VT_BOOL | byRefModifier);
      if ( byRefModifier != 0 )
      {
         short * temp = comobjMustMalloc(short,sizeof(*temp));
         *temp = result;
         V_BOOLREF(varg) = temp;
      }
      else
      {
         V_BOOL(varg) = result;
      }
         break;

Doing so uses the system's VarBoolFromR8() COM API function to obtain the numeric values for True and False that are expected by other applications.

  • comobj library handling Bools as numbers, causing heap to be overwritten
    (for ISDK/C 5.01b)

Bug: When calling a method of a COM object, the comobj library passes boolean arguments as numbers, which can cause the heap to be overwritten when used in conjunction with .NET COM objects.

Fix : In se501/src/lib/comobj/comobj.cpp, around line 2372, in the SE_TYPE_BOOLEAN case statement, there is a statement that looks like this:

      V_VT(pCurVar) = VT_R8 | passByRefValue;

Replace that statement with this one:

      V_VT(pCurVar) = VT_BOOL | passByRefValue;

Approximately ten lines below, within that same case statement, there is a line that looks like this:

      V_R8(pCurVar) = lVar;

Replace that statement with this one:

      V_BOOL(pCurVar) = (short)lVar;

  • COM object methods returning an array may cause an assertion
    (for ISDK/C 5.01b)

Bug: Calling a method of a COM object that returns an array may cause an assertion around line 900 in src/lib/comobj/comobj.cpp, function CreateReturnedVariant().

Fix : In se501/src/lib/comobj/comobj.cpp, around line 959, there is an else statement containing a for loop that looks like this:

      for( i = lowerBound; i <= upperBound; i++ )
      {
         VARIANT v;
         indicies[dim] = i;
         /* Get the element from the safe array */
         /* I'm making an assumption here, which is the elements of the
          * array will be VARIANTS.
          */
         hr = SafeArrayGetElement(psa,indicies,&v);

         if(FAILED(hr))
         {
            ReportComError( se, hr, &excepInfo );
         }

         CreateReturnedVariant(se,v,wName);

         seAssign(se, seRet, SE_NUM(i), SE_RETURN, SE_VALUE);
         sePutUndefined(se, SE_RETURN, SE_VALUE);
      }

Replace that entire for loop with this one:

      for( i = lowerBound; i <= upperBound; i++ )
      {
         VARIANT v;
         VARTYPE vt;
         VariantInit(&v);
         indicies[dim] = i;
         /* Get the element from the safe array */
         /* I'm making an assumption here, which is the elements of the
          * array will be VARIANTS.
          */
         hr = SafeArrayGetVartype(psa, &vt);

         if(FAILED(hr))
         {
            ReportComError( se, hr, &excepInfo );
         }

         V_VT(&v) = vt;

         switch (vt) /* default to original assumption of variant */
         {
            case VT_BOOL:
               hr = SafeArrayGetElement(psa,indicies,&(V_BOOL(&v)));
               break;
            case VT_BSTR:
               hr = SafeArrayGetElement(psa,indicies,&(V_BSTR(&v)));
               break;
            case VT_I4:
               hr = SafeArrayGetElement(psa,indicies,&(V_I4(&v)));
               break;
            case VT_UI4:
               hr = SafeArrayGetElement(psa,indicies,&(V_UI4(&v)));
               break;
            case VT_UI2:
               hr = SafeArrayGetElement(psa,indicies,&(V_UI2(&v)));
               break;
            case VT_I2:
               hr = SafeArrayGetElement(psa,indicies,&(V_I2(&v)));
               break;
            case VT_I1:
               hr = SafeArrayGetElement(psa,indicies,&(V_I1(&v)));
               break;
            case VT_UI1:
               hr = SafeArrayGetElement(psa,indicies,&(V_UI1(&v)));
               break;
            case VT_R4:
               hr = SafeArrayGetElement(psa,indicies,&(V_R4(&v)));
               break;
            case VT_R8:
               hr = SafeArrayGetElement(psa,indicies,&(V_R8(&v)));
               break;
            case VT_DECIMAL:
               hr = SafeArrayGetElement(psa,indicies,&(V_DECIMAL(&v)));
               break;
            case VT_DATE:
               hr = SafeArrayGetElement(psa,indicies,&(V_DATE(&v)));
               break;
            default:
               hr = SafeArrayGetElement(psa,indicies,&v);
         }

         if(FAILED(hr))
         {
            ReportComError( se, hr, &excepInfo );
         }

         CreateReturnedVariant(se,v,wName);

         seAssign(se, seRet, SE_NUM(i), SE_RETURN, SE_VALUE);
         sePutUndefined(se, SE_RETURN, SE_VALUE);
      }

  • seGetSourceFunc() being called an extra time for empty include files
    (for ISDK/C 5.01b)

Bug: If a script uses the #include preprocessor directive to include an empty file, the seGetSourceFunc() gets called with the seSourceGetLine flag an extra time after it returns False.

Fix : In se501/src/core/source.c, around line 1069, there is a comment that says "/* nothing was read at all */". It's in an if statement that looks like this:

   if( success )
   {
      if ( !sourceNextLine(*source,call,False,&success,True) )
      {
         /* nothing was read at all */
         (*source)->MemoryPtr = UNISTR("");
      }
   }

Deleting that whole "if( !success )" statement and its contents fixes this bug.

  • XML object not trimming whitespace from tail of incoming text elements
    (for ISDK/C 5.01b)

Bug: According to standard treatment of whitespace in XML text elements, the whitespace at the beginning and end of them should be discarded, but the XML object was only discarding the leading whitespace. This resulted in extra whitespace at the end of text elements that were converted to native objects from XML.

Fix : In se501/src/lib/xml/sexml.c, around line 1070, just before a break statement, add the following line of code:

    RemoveWhitespaceFromHeadAndTail(text_elem);

  • XML object mistreating special 'tag' and 'attribute' properties
    (for ISDK/C 5.01b)

Bug: The XML object is supposed recognize tag and attribute properties as being special properties, but the current implementation was not. This resulted in extra elements in outputted XML, and no attributes inside the tag itself.

Fix : First, be sure to apply previous XML errata items. At line 1625 of se501/src/lib/xml/sexml.c, in function obj_to_xml(), between the following two lines of code:

    concatenate_return_string(se,seGetString(se,obj,SEXML_TAG_MEMBER,NULL),True);
    concatenate_return_string(se,UNISTR(">\n"),False);
..insert the following block of code:
    if ( seExists(se,obj,SEXML_ATTRIBUTE_MEMBER) )
    {
       sememcount attrIndex;
       seobject attrs = seGetObject(se,obj,SEXML_ATTRIBUTE_MEMBER);
       sememcount lim = (sememcount)seGetLong(se,attrs,SE_STOCK(length));

       for( attrIndex=0;attrIndex< lim;attrIndex++ )
       {
          seobject attr = seGetObject(se,attrs,SE_NUM(attrIndex));

          concatenate_return_string(se,UNISTR(" "),False);
          concatenate_return_string(se,seGetString(se,attr,SEXML_TAG_MEMBER,NULL),True);
          concatenate_return_string(se,UNISTR("='"),False);
          concatenate_return_string(se,seGetString(se,attr,SEXML_CONTENT_MEMBER,NULL),True);
          concatenate_return_string(se,UNISTR("'"),False);
       }
    }
Also, at line 1668 of the same file and function, replace the following line of code:
    if( strcmp_sechar(name,UNISTR("tag"))==0 ) continue;
with this line of code:
    if( stricmp_sechar(name,UNISTR("tag"))==0 || stricmp_sechar(name,UNISTR("attribute"))==0 ) continue;

  • stricmp not defined for sexml when built as dynamic library on Unix platforms
    (for ISDK/C 5.01b)

Bug: The stricmp() function is not being defined for Unix platform extlibs. Since the SEXML library requires that function, compilation of the SEXML library as an extlib dynamic library fails.

Fix : In src/misc/utilstr.c, at about line 956 rename the stricmp_sechar() function to be stricmp(). Then, in se501/lib/makefile, around line 172, append the following line to the end of the definition of SRCEXTLIB:

    \
    $(SEISDKC_HOME)/src/misc/utilstr.c
Also, append the following line to the end of the definition of OBJEXTLIB around line 179:
    \
    seextlib/release/utilstr.o
Finally, append the following line to the end of the definition of OBJEXTLIB.DBG around line 187:
    \
    seextlib/debug/utilstr.o

  • seEval() does not honor SE_INFREQUENT_CONT flag when interpreting a function object
    (for ISDK/C 5.01b)

Bug: When calling seEval() to interpret a function object (using the SE_FUNC interp_type flag) in combination with the SE_INFREQUENT_CONT flag, the SE_INFREQUENT_CONT flag will be ignored. This results in the application's seContinueFunc to get called far more frequently than would be expected.

Fix : In src/core/se501.c, function seEvalFunc(), at about line 5911 replace the following statement:

   call->resetContinueCount = ( (flags & JSE_INTERPRET_INFREQUENT_CONT) != 0 ) ? 
                              (uword32)JSE_INFREQUENT_COUNT : 1 ;
with this one:
   call->resetContinueCount = ( (flags & SE_INFREQUENT_CONT) != 0 ) ? (uword32)JSE_INFREQUENT_COUNT : 1 ;

  • XML object creates faulty output sometimes
    (for ISDK/C 5.01b)

Bug: The output generation code in the SEXML library doesn't output the correct XML markup when an object has a property that is an Array, or if the object has the special .tag and .element properties

Fix : Replace se501/src/lib/xml/sexml.c with the one located here: ftp://ftp.nombas.com/pub/isdkeval/se501/sexml.c

  • XML.toText(), XML.toFile() including SE_DONTENUM properties in output
    (for ISDK/C 5.01b)

Bug: The output generation code in the SEXML library includes object properties marked as SE_DONTENUM in the text it outputs. This results in incorrect XML output, and can sometimes result in an infinite recursion.

Fix : In src/lib/xml/sexml.c, function obj_to_xml(), at about line 1637 (below the statement "seconstcharptr name = seObjectMemberName(se,obj,SE_INDEX(i),NULL);") add the following statement:

   if ( seGetAttribs(se, obj, SE_INDEX(i)) & SE_DONTENUM )
   {
      continue;
   }

  • string.replace can crash or return incorrect results when \b is used at the beginning of a regular expression
    (for ISDK/C 5.01b)

Bug: String.prototype.replace() can crash when built in MBCS mode, or give incorrect results when built in ASCII or UNICODE modes, when a regular expression starting with \b is passed as the first argument. Here is an example of what can cause a crash:

   "foo car".replace(/\bc/g, "b")

Fix : In src/lib/ecma/seregex.c, function seregex_match(), at about line 1398 (below the comment "/* match word boundary */") change this statement

   a = IsWordCharAtPosition(stringStart,stringEnd,PREVIOUS_SECHARPTR(execute.str,stringStart));

to be

   a = ( execute.str == stringStart ) ? False : 
       IsWordCharAtPosition(stringStart,stringEnd,PREVIOUS_SECHARPTR(execute.str,stringStart));

  • string.split is not ignoring the global flag on regular expressions
    (for ISDK/C 5.01b)

Bug: String.prototype.split() should ignore the global flag if it is set on the matching regular expression, according to the final note in section 15.5.4.14 of the EcmaScript. The ScriptEase engine is not ignoring that flag.

Fix : In src/lib/ecma/seobject.c, function SplitMatch(), at about line 2830 change this block

   struct seEvalParams params;
   seobject tmpObj;
   
   memset(&param,0,sizeof(params));
   params.default_this = R

to be

   struct seEvalParams params;
   seobject tmpObj;
   sebool restore_global_flag = seGetBool(se,R,SE_STOCK(global));
   
   /* split should ignore the global flag */
   if ( restore_global_flag )
      seMustPutBool(se,R,SE_STOCK(global),False);
   
   memset(&params,0,sizeof(params));
   params.default_this = R;

and near the end of that block, around line 2850, change this block

      else
{
ret = NULL;
}
seFreeObject(se,tmpObj);
}
seFreeObject(se,stack);

to be

      else
{
ret = NULL;
}
seFreeObject(se,tmpObj);
if ( restore_global_flag )
seMustPutBool(se,R,SE_STOCK(global),True);
}
seFreeObject(se,stack);

  • assert or invalid global pop on seExec() if params supplied to seStart()
    (for ISDK/C 5.01b)

Bug: If seEval(...SE_START...,params) is called with params!=NULL, then an ASSERT may be triggered or an invalid global may be restored at the end of seExec() or seEnd().

Fix : In src/core/call.h, change both instances (around lines 1132 and 1324) of

   struct seEvalParams *params

with

   uword8 pop_global_on_seEnd

and in src/core/se501.c, function seEvalFunc(), replace (near line 5981)

   start_info->params = params;

with

   start_info->pop_global_on_seEnd = params!=NULL && params->global!=NULL;

and in function seEval(), replace (near line 6519)

   newc->params = params;

with

   newc->pop_global_on_seEnd = params!=NULL && params->global!=NULL;

and in function seExec() replace (near line 6678)

   if( call->start_info->params!=NULL && call->start_info->params->global!=NULL )

with

   if( call->start_info->pop_global_on_seEnd )

and replace (near line 6703)

   sebool need_to_restore = call->params!=NULL && call->params->global!=NULL;

with

   sebool need_to_restore = call->pop_global_on_seEnd;

and in function seEnd() replace (near line 6737)

   sebool need_to_restore = call->params!=NULL && call->params->global!=NULL;

with

   sebool need_to_restore = call->pop_global_on_seEnd;

and finally replace (near line 6763)

   if( call->start_info->params!=NULL && call->start_info->params->global!=NULL )

with

   if( call->start_info->pop_global_on_seEnd )

  • internal function may cause assertion in call.c
    (for ISDK/C 5.01b)

Issue: A function containing an inner function may cause an assertion to be thrown around line 774 (`SEVAR_GET_TYPE(wv)>=VReference').

Fix : In src/core/se501.c around line 5916 there is a block of code like this:

   if( flags&SE_START )
   {
      struct evalFuncStart *start_info;

      start_info = (struct evalFuncStart *)secoreAlloc(call,NULL,sizeof(struct evalFuncStart),SE_DEFAULT);

On the line just above that if statement, add this statement:

    SEVAR_INIT_UNDEFINED(CALL_NEWSCOPE(call));

  • string.replace() may get caught in near-infinite loop
    (for ISDK/C 5.01b)

Issue: If string.replace() is called using the global flag and such that the result of the search expression replaces the null-patch at the end of the line, then replace may run for a long long while (until a memory object is returned). This is an example of a problem script.

   "a".replace( /a*/g, "stuff" );

Fix : In src/lib/ecma/seobject.c make the following changes:

1) near line 3492 replace the definition of the replace_string() function from this:

    static void JSE_NEAR_CALL replace_string(... 

to this

   static sememcount JSE_NEAR_CALL replace_string(...

2) replace the last line of the replace_string() function (around line 3686) from this:

   return;

to this

   return replace_len;

3) in function string_which_search_helper(), near line 3762, follow this line:

   seobject eval_ret = seGetObject(se,SE_RETURN,SE_VALUE);

with this additional line

   sememcount replace_len = 0;

and about seven lines below that replace

   replace_string(se,temp = ...

with

   replace_len = replace_string(se,temp = ...

4) around line 3788 of the same function replace this block

   if( new_index==last_index )
   {
      new_index++;

with this

   if( new_index == (slong)(last_index+replace_len) )
   {
      new_index = 1 + (last_index+replace_len);

  • Variable scoping incorrect within nested functions
    (for ISDK/C 5.01b)

Issue: This issue is best described by the following script:

   function foo()
   {
      var a = 7;
   
      function foo1()
      {
         function foo2()
         {
            return a;
         }
   
         return foo2();
      }
   
      return foo1();
   }
   var x = foo();

Currently, the nested function foo2() cannot find the variable "a", resulting in an error being thrown.

Fix : In src/core/call.c, function callFunction(), around line 747 there is a comment that starts

    /* Build the saved scope chain ... 

A few lines below that is a for( ; ; ) loop. After that for loop add this block of code:

   /* Now add the current function's saved scope chain to the new scope
    * chain we are creating.
    */
   if ( funcvar->data.object_val.hSavedScopeChain != NULL )
   {
      sememcount lookin;
      sememcount used;
      hSEObject cur_chain;
   
      HSEOBJECT_BRUTE_ASSIGN(cur_chain,funcvar->data.object_val.hSavedScopeChain);
      used = SEOBJECT_GET(call,cur_chain,used);
   
      for ( lookin = 0; lookin<used; lookin++ )
      {
         hSEMembers mems;
         wSEVar tmp;
      
         mems = SEOBJECT_GET(call,cur_chain,hsemembers);
         LOCK_READ_MEMBERS(call,mems);
      
         tmp = STACK_PUSH;
      
         SEVAR_COPY(tmp,SEMEMBERS_GET_sevar(call,mems,lookin));
         SEASSERT( SEVAR_GET_TYPE(SEMEMBERS_GET_sevar(call,mems,lookin))==VObject );
      
         seobjCreateMemberCopy(call,new_chain,SE_NO_VARNAME,tmp,SE_DEFAULT);
   
         STACK_POP;
      }
   }

  • string.replace() incorrect if first arguments is not a RegExp object
    (for ISDK/C 5.01b)

Bug: If the first parameter to String.prototype.replace() is not a RegExp object then it will be compiled into a RegExp object. This is incorrect behavior and based on an incomplete version of the EcmaScript specification. Instead, if the first arguments is not a RegExp object then it should be converted into a string and a direct string replacement should follow.

Fix : In src/lib/ecma/seobject.c, replace the function Ecma_String_replace() at about line 4022 with the code at ecma_string_replace.c

  • invalid debug assertion if seContinueFunc() sets SE_RETURN,SE_ERROR during script return statement
    (for ISDK/C 5.01b)

Problem: If a script happens to be executing a return statement when seContinueFunc() is called and sets the SE_RETURN,SE_ERROR flag, then an SE_ASSERT() statement will be triggered. That SE_ASSERT should not be triggered.

Fix : In src/core/secode.c, function secodeInterpret(), within "case seReturnExpr:" around line 2639, change this code:

   if ( !run_iterative )
      callMayIContinue(call);

to this

   if ( !run_iterative && !callMayIContinue(call) )
   {
      callError(call,textcoreMAYICONTINUE);
      return False;
   }

for 5.01a --

  • seGetSourceFunc() callback being called an extra time when script is missing a closing brace
    (for ISDK/C 5.01a)

Issue: When a script that is missing a closing brace ('}') is being compiled by the ScriptEase engine, the seGetSourceFunc() callback of the seContextParams structure gets called by the engine with the seSourceGetLine flag one time too many. That is to say, after the seGetSourceFunc() has been called with the seSourceGetLine flag and has returned False once, on the next call to seGetSourceFunc() the ScriptEase engine should pass it the seSourceClose flag, but instead the engine calls it one more time passing it the seSourceGetLine flag before calling it a final time passing it the seSourceClose flag. This can be a source of error if the seGetSourceFunc()'s seSourceGetLine handler does not expect to be called anymore once it has returned False to the ScriptEase engine.

Fix : To fix this issue, go to the secompileStatement() function in src/core/statemnt.c. Within the switch statement, there is a case statement for the character '{'. In that case statement (at approx. line 975), add the following code inside the while() loop, before the code already in that loop:

      if ( tokType(This->token)==seTokEOF )
      {
         success = False;
         callQuit(call, textcoreBAD_PRIMARY);
         break;
      }

                                

So now your while() loop should look like this:

   while( tokType(This->token)!='}' )
   {
      if ( tokType(This->token)==seTokEOF )
      {
         success = False;
         callQuit(call, textcoreBAD_PRIMARY);
         break;
      }

      if( !secompileStatement(This) )
      {
         success = False;
         break;
      }
   }

  • seExec() returning prematurely when SE_INFREQUENT_CONT flag used to initialize secontext
    (for ISDK/C 5.01a)

Bug: seExec() returns on any throw statement (caught or uncaught), regardless of the SE_INFREQUENT_CONT flag being used to initialize the context

Fix : To fix the source code in src/core/secode.c, function secodeInterpret(), at about line 744 replace:

   return secode_reasonToQuit(call,False);

with

   if ( !(ret = secode_ReasonToQuit(call,False,return_immediate_from_any_seReturn)) ||
         return_immediate_from_any_seReturn )
   {
      return ret;
   }

  • seMustPutXXX() and seMustPutDirectXXX() unsetting most variable attributes
    (for ISDK/C 5.01a)

Bug: The seMustPutXXX() and seMustPutDirectXXX() functions strip variable attributes, such as SE_DONTENUM and SE_READONLY, from the variable on which they are called.

Fix : A simple workaround is to call seSetAttribs after calling seMustPutXXX() and seMustPutDirectXXX(). Or to fix the source code in src/core/se501.c, function sePutMember(), at about line 3225 replace:

   seobjNewMember(call,obj,name,tmp,SE_DEFAULT,SE_NM_UPDATE);

with

   seobjNewMember(call,obj,name,tmp,attr,SE_NM_UPDATE);

Also, at about line 3292 replace:

   seobjNewMember(call,obj,name,tmp,SE_DEFAULT,SE_NM_UPDATE);

with

   seobjNewMember(call,obj,name,tmp,attrib,SE_NM_UPDATE);

  • sePutWrapper() ignoring the varFlags (variable attributes) parameters
    (for ISDK/C 5.01a)

Bug: The sePutWrapper() varFlags parameter (used to set variable attributes such as SE_DONTENUM) is being ignored.

Fix: A simple workaround is to call seSetAttribs after calling sePutWrapper(). Or to fix the source code in src/core/se501.c, function sePutWrapperEx(), at about line 5073 replace:

   sePutMember(call,obj,type,memdata,flags,temp_put);

with

   if ( !sePutMember(call,obj,type,memdata,flags,temp_put)
     || SE_DEFAULT != varFlags )
   {
      if ( !IS_STOCK_OBJ(obj) )
         seSetAttribs(se,obj,type,memdata,(seAttributes)varFlags);
   }

  • SEDBC library sometimes references uninitialized variables
    (for ISDK/C 5.01a)

Problem: In src/lib/sedbc/jse_rs_s.c, some variables can be referenced before they are initialized due to two continue statements preceeding their initializations.

Fix: In src/lib/sedbc/jse_rs_s.c, function FindSQLToken(), initialize the variables bInLiteral, bInBrackets, nLeftBrackets, and nRightBrackets before the continue statements; for instance, at line 45 instead of line 69.

  • SEDBC library allocates unnecessary memory on stack
    (for ISDK/C 5.01a)

Problem: In src/lib/sedbc/jse_db.c, a few buffers were being allocated on the stack instead of on the heap, which caused some embedded platforms to run out of stack space.

Fix: In src/lib/sedbc/jse_db.c, function BuildErrorString(), declare the variables named lpszMsg, lpszState, and lpszNative as sedbccharptr's instead of sedbcchar arrays. Next allocate memory to those variables as shown below:

   lpszMsg = (sedbccharptr)seGCMalloc(sedbc->se, \
      (sememcount)((SQL_MAX_MESSAGE_LENGTH + 1) * sizeof(sedbcchar)));
   lpszState = (sedbccharptr)seGCMalloc(sedbc->se, \
      (sememcount)((SQL_SQLSTATE_SIZE + 1) * sizeof(sedbcchar)));
   lpszNative = (sedbccharptr)seGCMalloc(sedbc->se, \
      (sememcount)(50 * sizeof(sedbcchar)));

Then at the end of the function, below the func_exit label, free that memory using seGCFree().

  • Math.random() is not very random on systems with 16-bit integers
    (for ISDK/C 5.01a)

Bug: On systems compiled with 16-bit integers, Math.random() always generates numbers very close to 0.0 or 1.0 (e.g. 0.0545345 or 0.992322), and not well-spread between 0 and 1.

Fix: In src/lib/ecma/mathobj.c, function Ecma_Math_random(), change this line:

   int r[5];

to this:

   uword32 r[5];

  • Date parser not recognizing 12 AM or "UTC"
    (for ISDK/C 5.01a)

Problem: When parsing a date/time with "12:00 AM UTC" the date parser is not recognizing this as midnight, but is instead registering that time as noon. Also, although the ECMAScript specification sets "GMT" as the tag for declaring universal time, it has become common to also use "UTC".

Change: In src/lib/ecma/sedate.c, function do_parse(), at around line 852, just before the comment that begins "/* if there is a PM anywhere..." add this code:

   /* if it is 12, but 12 AM, then that time is really 0 */
   if ( time[0] == 12  &&  strstr_sechar(DateBuf,UNISTR("am")) )
      time[0] = 0;

and then at about line 974 change this code

   gmt = strstr_sechar(DateBuf,UNISTR("gmt"));
   if ( gmt == NULL )

to this

   if ( NULL == (gmt = strstr_sechar(DateBuf,UNISTR("gmt")))
     && NULL == (gmt = strstr_sechar(DateBuf,UNISTR("utc"))) )

    Function constructor causes swapping for created functions
    (for ISDK/C 5.01a)

Problem: When JSE_MULTIPLE_GLOBAL is defined (the default), any anonymous function created at runtime with the Function constructor will preserve the global from when the Function library was loaded (usually at program initialization). This will cause the global to change to the original global whenever that anonymous function is later called.

Change: To keep the Function constructor from restoring its own global replace add the SE_KEEP_GLOBAL line 2296 of src/lib/ecma/seobject.c so it becomes:

   SE_CLASS( JseStr(se,Function), Ecma_Function_construct, 0, -1, \
             SE_SECURE|SE_KEEP_GLOBAL, SE_DONTENUM )

  • String match function should return null on no match
    (for ISDK/C 5.01a)

Issue: According to the commonly recognized ECMAScript Edition 3 Errata, string.match should return NULL if there are no items matched. This differs from the ECMAScript document, and from our 5.01a code, which would return a zero-length array.

Change: To get the return-null behavior, In src/lib/ecma/seobject.c, near the end of string_which_search_helper() (at about line 3839) replace this code:

   if( mode==SE_MATCH_MODE )
   {
      sePutObject(se,SE_RETURN,SE_VALUE,ret);
   }

with

   if( mode==SE_MATCH_MODE )
   {
      #if 1  /* this part of the code is a result of the ECMA-262 errata */
      if ( array_index == 0 )
         sePutNull(se,SE_RETURN,SE_VALUE);
      else
      #endif
         sePutObject(se,SE_RETURN,SE_VALUE,ret);
   }

  • seGetSourceFunc(...seSourceGetLine...) called twice if first call returns False
    (for ISDK/C 5.01a)

Bug: If seGetSourceFunc(...seSourceGetLine...) (aka seGetSourceFunc(...SE_SOURCE_GETLINE...)) returns False the first time it is called, it will be called again a second time.

Fix: In src/core/source.c, function sourceNewFromFile(), change the code after !sourceNextLine() (around line 545) from:

   This->MemoryPtr = UNISTR("");

to

   *Success = False;

  • SE_GF_NOCALLBACKS errata fix causes SE_GF_DIRECT failure on strings
    (for ISDK/C 5.01a)

Bug: After apply the SE_GF_NOCALLBACKS errata posted below, calls to sePutDirectString() or sePutStringEx(...SE_GF_DIRECT) will cause memory allocation errors.

Fix: After applying the errata posted below, edit src/include/se501.h and change (near line 632):

   #define SE_PS_USEPOINTER         0x004
   #define SE_PS_BORROWPOINTER      0x008

to

   #define SE_PS_USEPOINTER         0x020
   #define SE_PS_BORROWPOINTER      0x040

  • memory leak with array.toSource
    (for ISDK/C 5.01a)

Bug: A memory buffer remains unreleased for each call to Array.prototype.toSource. This would happen any time ToSource is applied to an instance of an Array, or to any object containing an instance of an Array.

Fix: In src/lib/ecma/seobject.c, function Ecma_Array_toSource, the following should be added as the last line of the function at about line 1465:

   dynamicBufferTerm(&buffer);

  • string.split returns undefined element 0 if no match
    (for ISDK/C 5.01a)

Bug: If String.prototype.split(delimeter) is called, but there is no delimeter matched, then this function should return a 1-element array with the original string as element 0. Instead it is wrongly returning and undefined type as element 0.

Fix: In src/lib/ecma/seobject.c, function Ecma_String_split, at about line 2945 this statement:

   seAssign(se,ret,SE_NUM((sememcount)seGetLong(se,ret,SE_STOCK(length))),
            SE_WRAPPER_TEMP, SE_MEM("temp"));

should be changed to:

   sePutString(se,ret,SE_NUM((sememcount)seGetLong(se,ret,SE_STOCK(length))),str,s);

  • converting a recursive array to a string can crash
    (for ISDK/C 5.01a)

Bug: In an array contains a recursive element that recursively refers back to the array, and if the array is then converted to a string, then the scriptease engine will crash. The following script demonstrates the problem:

   var a = new Array( "a", "b", "c" );
   a[1] = new Array( a, 2, 3 );
   var foo = "" + a; // will crash here from recursion

Fix: In src/lib/ecma/seobject.c, function Ecma_Array_join, after the declaration of variables (around line 662) add this block:

   #define PREVENT_RECURSION_NAME "join recursed"
   /* if this object was already visited, then just return a blank string */
   if ( seExists(se,SE_THIS,SE_HIDDEN_MEM(PREVENT_RECURSION_NAME)) )
   {
      sePutString(se,SE_RETURN,SE_VALUE,UNISTR(""),0);
      return;
   }
   sePutBool(se,SE_THIS,SE_HIDDEN_MEM(PREVENT_RECURSION_NAME),True);

and add the following as the final line of function Ecma_Array_join:

   seDelete(se,SE_THIS,SE_HIDDEN_MEM(PREVENT_RECURSION_NAME));

  • no flag provided to bypass dynamic callbacks, but allow for prototype chain
    (for ISDK/C 5.01a)

Bug: SE_GF_DIRECT (as used by the seGetDirect and seGetEx calls) bypasses the dynamic callbacks and the prototype chain. SE_GF_NOPROTOTYPE bypasses the prototype chain but not the callbacks. There is no corresponding call to skip dynamic callbacks but still allow access via the prototype chain.

Fix: Add a new SE_GF_NOCALLBACKS option to bypass callbacks but still allow access via the prototype chain. This fix assumes that the HP_DIRECTCHECK errata has already been applied. In src\include\se501.h at about line 617 replace this line:

   #define SE_GF_DIRECT             0x001

with these two lines:

   #define SE_GF_NOCALLBACKS        0x001
   #define SE_GF_DIRECT             (SE_GF_NOPROTOTYPE|SE_GF_NOCALLBACKS)

and in src/core/var.h, near line 363 change

   #define GV_NO_PROTOTYPE 1
   #define GV_NO_DYNAMIC   2

to

   #define GV_NO_PROTOTYPE SE_GF_NOPROTOTYPE
   #define GV_NO_DYNAMIC SE_GF_NOCALLBACKS

and then in src/core/se501.c change every reference from

   SE_GF_DIRECT

to

   SE_GF_NOCALLBACKS

and also in src/core/se501.c, function seGetMember(), at around line 2574 change

   direct = TRUE;

to

   flags |= SE_GF_NOCALLBACKS;

finally, about 17 lines later, replace this block:

   int f = ( (flags & SE_GF_DIRECT) || direct )
         ? ( GV_NO_PROTOTYPE | GV_NO_DYNAMIC )
          : ( ( flags & SE_GF_NOPROTOTYPE ) ? GV_NO_PROTOTYPE : GV_DEFAULT );
   SEVAR_INIT_OBJECT(tmpobj,obj);
   ret = sevarGetValue(call,tmpobj,name,temp_get,f);

with this

   SEVAR_INIT_OBJECT(tmpobj,obj);
   ret = sevarGetValue(call,tmpobj,name,temp_get,flags);

After applying this fix be sure to also apply the SE_GF_DIRECT failure on strings fix posted above.

  • calling byref function turns all local variables into references
    (for ISDK/C 5.01a)

Bug: If a byref function is called from within another function, all of the local variables in the outer function will be turned into references.

Fix: In src/core/secode.c, function secodeInterpret(), near line 829 this block of code:

   #if JSE_PASSBYREF==1
      if ( FUNCTION_PASSBYREF(function)
        || ( FUNCTION_IS_LOCAL(function)
          && with_tmp < ((struct LocalFunction*)function)->localItems.InputParameterCount
          && ((struct LocalFunction*)function)->localItems.items[with_tmp].passByRef ) )
        {
           /* In this case we have pass-by-reference */
           SEVAR_INIT_UNDEFINED(w_lhs);
           if( CALL_VAROBJ(call)==hSEObjectNull )
              callCreateVariableObject(call,NULL,0);
        }
   #endif
   
   SEVAR_COPY(w_lhs,w_rhs);

should be changed to this code:

   #if JSE_PASSBYREF==1
      if ( FUNCTION_PASSBYREF(function)
        || ( FUNCTION_IS_LOCAL(function)
          && with_tmp < ((struct LocalFunction*)function)->localItems.InputParameterCount
          && ((struct LocalFunction*)function)->localItems.items[with_tmp].passByRef ) )
      {
         /* In this case we have pass-by-reference */
         SEVAR_INIT_UNDEFINED(w_lhs);
         if( CALL_VAROBJ(call)==hSEObjectNull )
            callCreateVariableObject(call,NULL,0);
   
         SEVAR_COPY(w_lhs,w_rhs);
      }
      else
      {
         /* The local variable could be a reference into the variable object.
          * If this is true, it will be passed by reference even though it
          * should not be. To avoid this, we now copy the variable to the stack
          * and dereference it.
          */
         SEVAR_COPY(w_lhs,w_rhs);
         SEVAR_DEREFERENCE(call,w_lhs);

      }
   #else
      /* No pass by reference, so just copy the variable to the stack */
      SEVAR_COPY(w_lhs,w_rhs);
   
   #endif

  • too many callbacks for global get and for hasprop returning HP_DIRECTCHECK
    (for ISDK/C 5.01a)

Bug: If the global object has a get callback, then get is called too often while initializing code. Also, if any hasProp callback is returning HP_DIRECTCHECK then the get callback is being called, although it shouldn't.

Fix: In src/core/call.c, function callFunction(), near line 768 this block of code:

   wSEVar wLoc = STACK_PUSH;
   wSEVar wTmp = STACK_PUSH;
   
   SEVAR_INIT_UNDEFINED(wTmp);
   SEVAR_INIT_OBJECT(wLoc,CALL_VAROBJ(call));
   GetDotNamedVar(call,wLoc,GetSEStringTableEntry(call,ourname,NULL),GDNV_DONT_DELETE);
   if( hif_func!=hSEObjectNull )
   {
      SEVAR_INIT_OBJECT(wTmp,hif_func);
      if ( VObject == SEVAR_GET_TYPE(CALL_NEWSCOPE(call)) )
      {
         hSEObject hobj;
   
         HSEOBJECT_BRUTE_ASSIGN(hobj,SEVAR_GET_OBJECT(CALL_NEWSCOPE(call)));
         SEASSERT( hSEObjectNull != hobj );
         if( 0data.object_val.hSavedScopeChain,hobj);
         }
      }
   }
   else
   {
      SEVAR_INIT_UNDEFINED(wTmp);
   }

should be changed to this code:

   wSEVar wLoc = STACK_PUSH;
   wSEVar wTmp = STACK_PUSH;
   
   if( hif_func != hSEObjectNull )
   {
      SEVAR_INIT_OBJECT(wTmp,hif_func);
      SEVAR_INIT_OBJECT(wLoc,CALL_VAROBJ(call));
      GetDotNamedVar(call,wLoc,GetSEStringTableEntry(call,ourname,NULL),GDNV_DONT_DELETE);
      if ( VObject == SEVAR_GET_TYPE(CALL_NEWSCOPE(call)) )
      {
         hSEObject hobj;
   
         HSEOBJECT_BRUTE_ASSIGN(hobj,SEVAR_GET_OBJECT(CALL_NEWSCOPE(call)));
         SEASSERT( hSEObjectNull != hobj );
         if( 0<SEOBJECT_GET(call,hobj,used) )
         {
            HSEOBJECT_INIT_ASSIGN(wTmp->data.object_val.hSavedScopeChain,hobj);
         }
      }
   }
   else
   {
      SEVAR_INIT_UNDEFINED(wTmp);
      SEVAR_INIT_REFERENCE(wLoc,CALL_VAROBJ(call),ourname);
   }

Then in src/core/se501.c function seGetMember(), near line 2547 (about 22 lines below the "not_there:" target), replace the else block that begins with this line:

   wSEVar tmpobj = STACK_PUSH;

with this block

   wSEVar tmpobj = STACK_PUSH;
   sebool direct = FALSE;
   
   #if JSE_DYNAMIC_CALLBACKS==1
   ret = TRUE;
   SEVAR_INIT_UNDEFINED(tmpobj);
   /* If the object says it does not have the property,
    * believe it. Return FALSE with the undefined value.
    */
   if( (flags&SE_GF_DIRECT)==0
    && SEOBJ_IS_DYNAMIC_PROP(call,obj,hasProp)
    && !IS_HIDDEN_PROP(name) )
   {
      if( seobjCallDynamicProperty(call,obj,SE_HASPROP_CALLBACK,name,NULL,tmpobj) )
      {
         if ( HP_HASNOT == SEVAR_GET_SLONG(tmpobj) )
         {
            ret = FALSE;
            SEVAR_INIT_UNDEFINED(temp_get);
         }
      }
      else
      {
         if ( VNumber == SEVAR_GET_TYPE(tmpobj) )
         {
            if ( HP_DIRECTCHECK == SEVAR_GET_SLONG(tmpobj) )
               direct = TRUE;
         }
      }
   }
   ELSE_ALWAYS_COLLECT(call)
   
   if( ret )
   #else
      /* above calldyna would have caused GC */
      ALWAYS_COLLECT(call)
   #endif
   {
      int f = ( (flags & SE_GF_DIRECT) || direct )
            ? ( GV_NO_PROTOTYPE | GV_NO_DYNAMIC )
            : ( ( flags & SE_GF_NOPROTOTYPE ) ? GV_NO_PROTOTYPE : GV_DEFAULT );
      SEVAR_INIT_OBJECT(tmpobj,obj);
      ret = sevarGetValue(call,tmpobj,name,temp_get,f);
   
   }
   
   STACK_POP;

And in src/core/varutil.c, function seobjCallDynamicProperty(), replace "case SE_HASPROP_CALLBACK:" around line 2300 with this code:

   case SE_HASPROP_CALLBACK:
   {
      int cp = DYNA_CALLBACK1(callbacks->hasProp,prop_name);
   
      if ( cp < 0 )
      {
         SEASSERT( cp==HP_CHECK || cp==HP_DIRECTCHECK );
         done = False;
      }
      else
      {
         SEASSERT( cp==HP_HAS || cp==HP_HASNOT );
      }
      SEASSERT( result!=NULL );
      SEVAR_INIT_SLONG(result,cp);
      break;
   }

then around line 2665 replace these lines:

   STACK_POP;
   
   /* Call the 'get' to get the property */

with this block

   else
   {
      if ( VNumber == SEVAR_GET_TYPE(value) )
      {
         if ( HP_DIRECTCHECK == SEVAR_GET_SLONG(value) )
         {
            STACK_POP; /* value */
            goto standard_directcheck;
         }
      }
   }
   STACK_POP; /* value */
   
   /* Call the 'get' to get the property */

finally, around line 2719 replace this code

   # else
      /* on some occasions calldyna will happen and GC may happen, so force it always */

with this (only a label is added)

      standard_directcheck:
   #  else
         /* on some occasions calldyna will happen and GC may happen, so force it always */

  • hang on assigning to undefined variable if global object is SE_DYNA_UNDEF
    (for ISDK/C 5.01a)

Bug: If the global object is dynamic (i.e. setSetCallbacks has been called on SE_GLOBAL), and if jseopt.h defines JSE_CACHE_GLOBAL_VARS, and if a property of the global is of type undefined, then assigning to that property will result in an assertion being raised (if a debug build) or in the engine haning in an infinite loop.

Fix: In src/core/call.c, function secoreFindAnyVar(), at about line 1899, change this code:

   #  if JSE_DYNAMIC_CALLBACKS==1
      if ( obj_flag==0 || VUndefined != SEVAR_GET_TYPE(wslot) )
   #  endif

to this

   #  if JSE_DYNAMIC_CALLBACKS==1
      if ( !(obj_flag==0 || VUndefined != SEVAR_GET_TYPE(wslot)) )
         wslot = STACK0;
      else
   #  endif

  • Clib.fread() leaves unread parts of buffers uninitialized
    (for ISDK/C 5.01a)

Bug: If Clib.fread(...buffer_size...) reads less than buffer_size bytes, then the buffer size will be created large enough for buffer_size bytes and the parts of the buffer beyond what are read will be uninitialized and may contain random data. Instead, the buffer should not be expanded beyond the number of bytes that are read.

Fix: Replace the Clib_fread() function in src/lib/clib/sestdio.c with the code at clib_fread.c

  • Alignment errors with Clib *printf and *scanf floating-point on HP-UX
    (for ISDK/C 5.01a)

Bug: If a call to the Clib *printf or *scanf methods (e.g. Clib.sprintf) contains non-floating-point data types following a floating-point type, data alignment may be incorrect and invalid data or crashes will result. This problem appears only on HPUX systems.

Fix: Replace src/lib/clib/sefmtio.c with the file at sefmtio.c

   

Home | Scripting | Products | Purchase | Download | Support | Company

Copyright ©2001, Nombas, Inc. All Rights Reserved.
Questions? Visit
http://support.nombas.com/