Integration
SDK 5.00x Errata
Fixes Affecting Users of the ScriptEase
ISDKs
API Errata, version 5.00f
New, July 24, 2003
API Errata, version 5.00e
New, February 14, 2003
API Errata, version 5.00d
New, October 14, 2002
The
Details
for
5.00f -- (may apply to earlier versions)
- system
can become corrupted if number of objects in
use is greater than MARK_STACK_SIZE
(for ISDK/Java 5.00f)
Bug: If the number of objects in use is greater
than MARK_STACK_SIZE (defined in Call.jh) then
memory may become corrupted. This is a rare
oocurence and very difficult to duplicate. If
you have experienced such corruption when running
with very many objects, and if the problem is
difficult to duplicate, then this may be the
cause.
Fix:
In COM/Nombas/jse/Isdk/Garbage.jsrc, method
mark(), this block near line 670:
for( i=0;i<used;i++ )
{
SE_VAR var;
var = mems[i];
should
become:
for( i=0;i<used;i++ )
{
SE_VAR var;
int vn = mems[i].name;
if ( -1 != vn
&& StringTable.IsNormalStringTableEntry(vn)
&& (0 == (basecall.Global.stringTable.HashEntryFromVarName(vn).locks
& StringTable.SWEEP_BIT)) )
{
add_it = true;
break;
}
var = mems[i];
- cached
prototypes (Array, Function, Object, String)
miss __parent__ inheritance
(for ISDK/Java 5.00f)
Bug:
Some common objects have their Object.prototype
object cached for faster access. These objects
are Array, Function, Object, and String. When
refreshing this "prototype cache" the real objects
may not be found if inheritance is through the
__parent__ chain instead of through standard
_prototype chain. The resulting bug will usally
be that statements that use these cached prototypes
(e.g. new String(), "foo".toString()) will fail,
while objects that do not use this cache (e.g.
new Date()) will work.
Fix:
The method AssignGlobalPrototype() in COM/Nombas/jse/Isdk/Call.jsrc
should be repleaced with the version found at
ftp://ftp.nombas.com/pub/isdkeval/se500/assignglobalprototype_java.txt
- try/catch
grows internal stack
(for
ISDK/Java 5.00f)
Bug:
Each try/catch will leave one element on the
internal stack. The stack space is restored
whenever the containing function returns. But
if the function does not return then many try/catch
blocks will eventually throw an out-of-stack
error. For example, the following script would
eventually exhause internal stack space:
for ( ; ; )
{
try
{
throw "blah";
}
catch(e)
{
}
}
Fix:
In COM/Nombas/jse/Isdk/Secode.jsrc, method ReasonToQuit(),
remove all lines declaring or referencing the
variable w_new_loc.
- seCreateFiber()
with JSE_SECURE uses unreleased memory
(for
ISDK/Java 5.00f)
Bug:
If compiling with JSE_SECURE defined, then each
call to seCreateFiber() creates objects that
are not released until the top-level context
is destroyed.
Fix:
The simplest fix is to remove JSE_SECURE
from your JSEOPT.JH file. If compiling with
JSE_TASK_SCHEDULER and JSE_SECURE then in COM/Nombas/jse/Isdk/Call.jsrc,
method newSettings(), at about line 3758 replace
this line:
if( success && (this.prev == null||
with:
if( success && ((this.prev == null && this.fiber_prev == null) ||
- Null
Pointer Exceptions when working with fibers
(for
ISDK/Java 5.00f)
Bug:
Destroying a fiber with seDestroyContext() causes
Null Pointer Exceptions to be thrown when interpreting
in sibling contexts.
Fix:
All of the following changes are to be made
in COM/Nombas/jse/Isdk/Call.jsrc:
At
the beginning of the interpret(int, boolean,
boolean) method, around line 3213, remove this
line:
call.Global.api_mark++; /* all temps here on are cleaned when this mark is cleaned */
Next,
in the delete() method around line 3436, replace
this code:
# if JSE_TRACKVARS==1
if ( null == call.prev )
{
with
this:
# if JSE_TRACKVARS==1
if ( null == call.prev
# if JSE_TASK_SCHEDULER==1
&& null == call.fiber_prev
# endif
)
{
A
little further down in the delete() method,
around line 3468, remove this block of code:
{
boolean had_wrapper_temp = false;
SE_VAR old_ret = null;
byte old_state = FlowFlags.StateNormal;
/* delete any remaining temp vars */
SE500_CALL_KILL_TEMPVARS_GUTS(call);
call.Global.api_mark--; /* no more temps will be at this level */
}
A
couple lines down, remove this block of code
as well:
/* Kill all remaining temp stuff */
while( call.Global.api_local_temps.next!=null )
{
call.seTempFreeObject(call.Global.api_local_temps.next);
}
Finally,
a few more lines down you will find a call to
call.cleanupGlobal(). Insert this code directly
before that call:
boolean had_wrapper_temp = false;
SE_VAR old_ret = null;
byte old_state = FlowFlags.StateNormal;
/* delete any remaining temp vars */
SE500_CALL_KILL_TEMPVARS_GUTS(call);
- Empty
#defines ignored
(for ISDK/Java 5.00f)
Bug:
If a preprocessor macro is defined without a
body the engine will not consider it 'defined'.
Fix:
In COM/Nombas/jse/Isdk/SEDirective.jsrc, function()
method of the DefineHandler class, around line
153 find this block:
if ( WithinComment )
{
/* if ended within comment, then stop where that comment begins */
end = BeginComment;
}
and
add this else block:
else
{
end = i;
}
- The
#ifdef and #ifndef preprocessor directives behave
incorrectly
(for ISDK/Java 5.00f)
Bug:
The #ifdef and #ifndef directives rely on comparisons
against the ECMAScript undefined value to determine
if a symbol is defined. This behavior causes
errors when the directive is applied to an empty
macro. These directives now only test names
in respect to whether or not they have been
defined by #define, or are members of the SE.DEFINE
object.
Fix:
in COM/Nombas/jse/Isdk/Source.jsrc, method conditionalCompilationFilter(),
around line 598 change this line:
if ( !evaluateConditionalCompilation( call, SourceToEvaluate, \
TextCore.CCD_ifdef==find,true) )
to
this:
if ( !evaluateIfDef( call, SourceToEvaluate, TextCore.CCD_ifdef==find ) )
Next,
the sourceEvaluteIfDef() method needs to be
added to the Source class in COM/Nombas/jse/Isdk/Source.jsrc.
The source for this methodcan be found at ftp://ftp.nombas.com/pub/isdkeval/se500/ifdef.java
for
5.00e -- (may apply to earlier versions)
-
RegExp.$x
and RegExp.lastParen not overwriting previous
results with "undefined"
(for ISDK/Java 5.00e)
Bug:
When the results of a regular expression call
should result in undefined for for RegExp.$1...RegExp.$9
or RegExp.lastParen, the results of the most-recent
previous call are not over-written with undefined.
Fix:
In COM/Nombas/jse/libraries/SERegExp.jsrc, function
RegExp_ExecOrCallOrTest(), the three calls to
se.sePutUndefined(...) (at lines 609, 656, and
679) should be replaced with seMustPutUndefined(...).
- Number
toExponential() incorrect if fractionDigits
not specified
(for ISDK/Java 5.00e)
Bug:
Number.prototype.toExponential(fractionDigits)
is treating fractionDigits as 0 if unspecified.
Instead toExponential() should use as many digits
as necessary.
Fix:
In COM/Nombas/jse/libraries/ECMAObject.jsrc,
function Ecma_Number_toSomething(), at about
line 1825 a block of code should be added after
f = 0; as follows:
if ( _toExponential == toWhat )
{
String[] buffer = {null};
int cptr = 0;
/* convert using standard tostring rules */
Utility.EcmaNumberToString(buffer,x);
/* from buffer count how many digits are needed after the decimal,
* that's all digits minus 1
*/
if ( buffer[0].charAt(cptr) == '-' ) cptr++; /* skip any negative */
int length = buffer[0].length();
while ( cptr < length )
{
char c = buffer[0].charAt(cptr);
cptr++;
if ( '0' <= c && c <= '9' )
f++;
else if ( '.' != c )
break;
}
f--;
}
- Number
toPrecision() incorrect
(for ISDK/Java 5.00e)
Bug: Number.prototype.toPrecision(precision)
is converting precision digits beyond the decimal,
when it should be converting precision-1 digits.
Fix:
In COM/Nombas/jse/libraries/ECMAObject.jsrc,
function Ecma_Number_toSomething(), at about
line 1943 the entire toPrecision block should
be replaced with this code:
else
{
senumber abs_x = Math.abs(x);
/* field width must be an int */
/* if x>=pow(10,-6) && < pow(10,f), use fixed-point notation
* otherwise, use exponential notation */
if( (Math.pow((senumber)10,(senumber)-6) > x= abs_x ) &&
(abs_x < Math.pow((senumber)10,(senumber)f)) )
{
senumber f10 = Math.log(abs_x)/Math.log(10);
int d10 = (int)f10;
f -= d10;
if ( !jseIsNegative(f10) )
f--;
pattern = "0";
if ( f > 0 )
{
pattern += ".";
for ( int i = 0; i < f; i++ )
pattern = pattern + "0";
}
else
{
pattern = "0.00";
}
form.applyPattern( pattern );
buffer = form.format(x);
}
else
{
java.math.BigDecimal foo = new java.math.BigDecimal(x);
foo = foo.movePointLeft(f);
foo = foo.setScale(0,BigDecimal.ROUND_HALF_UP);
foo = foo.movePointRight(f);
f = f-1;
pattern = "0";
if ( f > 0 )
pattern += ".";
for ( int i = 0; i < f; i++ )
pattern = pattern + "0";
pattern = pattern + "E0";
form.applyPattern( pattern );
buffer = form.format(foo.doubleValue());
buffer = convertExponentialFormat(buffer);
}
}
Also, add this method to the ECMAObject class
(in COM/Nombas/jse/libraries/ECMAObject.jsrc):
static private String convertExponentialFormat(String format)
{
StringBuffer temp = new StringBuffer();
/* Convert the 'E' to 'e+' or 'e-' */
for( int i=0, len = format.length(); i<len; i++ )
{
char c = format.charAt(i);
if ( c == 'E' )
{
temp.append("e");
if ( format.charAt(i+1) != '-' )
{
temp.append("+");
}
}
else
{
temp.append(c);
}
}
return temp.toString();
}
- discrepencies
using delete on global variables
(for ISDK/Java 5.00e)
Bug:
When delete is used on global variables that
were not created with the var keyword, the variables
are not being deleted or the wrong boolean is
being returned.
Fix:
In
COM/Nombas/jse/Isdk/SECompile.jsrc, method operatorExpression()
under case seTokDelete:, replace this else block
at about line 2916:
else { /* not a reference, return 'true', 11.4.1 */ ... }
with
this code:
else if( this.expr.type==SEExpression.GLOBAL )
{
this.addItem(sePushGlobalObject);
this.addItem(seDeleteMember,this.expr.name);
}
else
{
/* not a reference, return 'true', 11.4.1 */
this.discard();
this.addItem(sePushTrue);
}
Then
in COM/Nombas/jse/Isdk/Call.jsrc, function(),
find this comment:
/* no need to set the attributes directly, the variable object
* cannot be referenced by the script, which makes it
* effectively 'DontDelete'.
*/
which
is no longer true. Replace it with:
SEVAR_GET_REFBASE(wLoc).setAttributes(this, (int)wLoc.num_val,
(byte)SE.DONTDELETE);
and
in COM/Nombas/jse/Isdk/_SEObject.jsrc, method
deleteMember(), at about line 1502 the case
with the comment
/* member doesn't exist; don't delete what does not exist */
should
be changed to return
true;
- string
replace, if no matches found, is not returning
the initial string
(for
ISDK/Java 5.00e)
Bug:
If String.prototype.replace() is called and
no replacement is made, then the original string
should be returned.
Fix:
In COM/Nombas/jse/libraries/ECMAString.jsrc,
function string_which_search_helper(), at about
line 1116 is a comment "...could be no match..."
After the seAssignConvert() call just below
that comment this function should return. With
the return statement that block becomes:
/* could be no match, if replace, return the string from thisVar */
if( se.seGetType(SE.RETURN,SE.VALUE) == SE.TYPE_NULL &&
mode == SE_REPLACE_MODE )
{
se.seAssignConvert(SE.RETURN,SE.VALUE,SE.THIS,SE.VALUE,SE.TOSTRING);
return;
}
for
5.00d -- (may
apply to earlier version)
- seCreateFiber
reinitializes function libraries
(for ISDK/Java 5.00d)
Problem: seCreateFiber is reinitializing the
function libraries, when they should be shared.
Because it reinitialized them in the same global,
it just overwrote the existing libraries resulting
in a performance decrease to 'redo' already-done
work.
Fix:
in COM/Nombas/jse/Isdk/Call.jsrc, the function
seCreateFiber, find this line at about 5791:
call.CallSettings = SE.EXIT_LEVEL|SE.NEW_DEFINES|SE.NO_INHERIT;
and
replace with this:
call.CallSettings = SE.EXIT_LEVEL|SE.NEW_DEFINES|SE.NO_INHERIT|SE.NO_LIBRARIES;
and in src/core/call.c, function callDelete(),
at at about line 1906, replace this block:
if( (((call.CallSettings & SE.NO_INHERIT) != 0) &&
((call.CallSettings & SE.NO_LIBRARIES) == 0)) ||
call.prev == null )
with
this
if( (((call.CallSettings & SE.NO_INHERIT) != 0) &&
((call.CallSettings & SE.NO_LIBRARIES) == 0)) ||
(call.prev == null
# if JSE_TASK_SCHEDULER==1
&& fiberSibling==null
# endif
) )
- Errors
with extremely large Date values
(for ISDK/Java 5.00d)
Problem: Date values larger than the maximum
allowable to new Date() can cause nearly-infinite
loops.
Fix:
In COM/Nombas/jse/Isdk/SEDate.jsrc, method do_date_construction(),
near line 895 find this block:
else
{
value = se.seGetNumber(SE.ARGS,SE.INDEX(0));
}
and
replace with this:
else
{
value = se.seGetNumber(SE.ARGS,SE.INDEX(0));
value = TimeClip(value);
}
- virtual-stack
growth if retrieving values after an exception
(for ISDK/Java 5.00d)
Problem: If an exception is generated during
a call to the SE API, items may be left on the
script stack. This is not likely to cause a
problem in a run-time system, but in debug mode
will cause the SE_API_RETURN() macro to emit
a "stack growth" assertion.
Fix:
In COM/Nombas/jse/Isdk/_SEVar.jh, in the macros
for SEVAR_DEREFERENCE, are two lines (lines
399 419) like this::
if( !CALL_QUIT(c) ) STACK_POP(c); \
in
both cases the CALL_QUIT() test should be removed,
so they both become:
STACK_POP(c); \
- dynamic
get is not being called if SEHasPropCallback
not implemented
(for ISDK/Java 5.00d)
Problem: If an object has dynamic callbacks
via seSetCallbacks, but does not implement a
hasProp callback, then the get callback should
be called to determine if the object has the
given property. This is not happening in 5.00d.
Fix:
in src/core/varutil.c, the function seobjHasProperty,
near the top (at about line 1296) is:
if( SEOBJ_IS_DYNAMIC_PROP(call,this,SEHasPropCallback) )
replace
with:
if( SEOBJ_IS_DYNAMIC_PROP(call,this,SEHasPropCallback)
|| SEOBJ_IS_DYNAMIC_PROP(call,this,SEGetCallback) )
and
then a few lines down (at about line 1305) immediately
after this comment:
/* Make sure that we initialize it in case GC happens */
add these lines:
if ( !SEOBJ_IS_DYNAMIC_PROP(call,this,SEHasPropCallback) )
{
handled = false;
}
- string.split()
incorrect if regular expression used as separator
(for ISDK/Java 5.00d)
Bug: String.prototype.split(separator) returns
the wrong results when separator is a regular
expression and does not match the first character
of the string.
Fix:
In COM/Nombas/jse/Isdk/ECMAString.jsrc, function
Ecma_String_split(), at about line 498(just
after the second call to SplitMatch) this statement:
if( z!=null );
should
be changed to:
if( z!=null && ((R==null) || se.seGetLong(z,SE.STOCK(JseStrID.index))==0) )
- seDestroyContext
cannot be called within seEval
(for ISDK/Java 5.00d)
Problem: seDestroyContext was written with the
assumption that no seEvals would be currently
executing inside it when called. Since people
want to be able to just abort and cleanup the
context, the function has been changed to support
this.
Fix:
COM/Nombas/jse/Isdk/Call.jsrc, replace the existing
seDestroyContext with this new version:
public void seDestroyContext()
{
SE_CALL call;
boolean again;
do
{
call = CALL_FROM_JSECONTEXT(this);
assert_is_context(call);
again = (call.prev != null);
Call.delete(call);
}
while( again );
}
- crash
with eval() in nested function
(for ISDK/Java 5.00d)
Bug: Crash in eval() inside nested function
calls. This bug applies to any wrapper function
trying to call seEval().
Fix:
COM/Nombas/jse/Isdk/Call.jsrc, function createVariableObject(),
at about line 1661 find:
while( !FUNCTION_IS_LOCAL(func_orig) \
|| (lookfunc!=null && lookfunc!=func_orig) || depth-->0 )
{
and
replace with
while( !FUNCTION_IS_LOCAL(func_orig) \
|| (lookfunc!=null && lookfunc!=func_orig) || depth>0 )
{
if( depth ) depth--;
- STACK_INFO
crashes within nested seEval()
(for ISDK/Java 5.00d)
Problem: Using STACK_INFO within nested interprets
can crash.
Fix:
COM/Nombas/jse/Isdk/Call.jsrc in the seGetMember
function, find this block at about line 1214:
save = init_call.save;
in_prev_call:
while(true)
{
and
change it to:
in_prev_call:
while(true)
{
save = scall.save;
- stock
objects passed to seEval with SE.FUNC will not
work
(for ISDK/Java 5.00d)
Bug: When calling seEval() with stock objects
and the SE.FUNC flag (e.g. seEval(...,SE.THIS,...,SE.FUNC,...))
the stock object will not be recognized. This
is most likely to show up when the object is
SE.NOWHERE as a result of an invalid call to
seGetObject().
Fix:
In COM/Nombas/jse/Isdk/Call.jsrc, method seEvalFunc(),
add this to the local variable declarations
at the top
SE_OBJECT realobj = seobjectTohSEObject(func_obj);
and
about 20 lines further down in the same function,
just before the statement "pushes += 2;",
replace this line:
SEVAR_INIT_OBJECT(func_var,func_obj.obj);
with this:
SEVAR_INIT_OBJECT(func_var,realobj);
- assert()
or memory leak from seEval(...SE_FUNC..) if
run-time error in script function
(for ISDK/Java 5.00d)
Problem: When using seEval() to call a function,
errors in the function could trigger assertions.
In release builds, this would result in a slight
memory leak.
Fix:
In COM/Nombas/jse/Isdk/Call.jsrc, function callFunctionFully(),
at about line 2700, replace this line:
if( !callMayIContinue(this) )
with
this:
if( !CALL_ERROR(this) && !callMayIContinue(this) )
and 5 lines further down remove the following
3 statements:
_SEVar ret = STACK_PUSH(this);
SEVAR_INIT_UNDEFINED(ret);
this.error(TextCore.MAYICONTINUE);
- SE_NEW_GLOBALS
flag for seEval() doesn't work
(for ISDK/Java 5.00d)
Problem: Specifying a new global in calls to
seEval using the seEval parameters structure
can fail to take effect.
Fix:
COM/Nombas/jse/Isdk/Call.jsrc, function seEval(),
at about line 9933, replace this line:
HowToInterpret &= ~SE.NEW_GLOBALS;
with
this:
settings &= ~SE.NEW_GLOBALS
- Function.prototype.apply()
not accepting null for thisObj parameter
(for ISDK/Java 5.00d)
Problem: Function.prototype.apply() should accept
null or undefined as the first parameter, using
the global object for these cases. Instead an
error message is generated.
Fix:
In COM/Nombas/jse/libraries/ECMAObject.jsrc,
function Ecma_Function_apply,
at about line 468replace this conditional:
if( argc > 0 )
with
this:
if( argc > 0
&& SE.TYPE_NULL < se.seGetType(SE.ARGS,SE.INDEX(0)) )
- seEval(...SE_FUNC...)
does not generate exception if object is not
a function
(for ISDK/Java 5.00d)
Problem: Calling seEval() with a function (the
SE.FUNC flag) will return false but will not
generate an exception and will not call the
seAttErrorFunc or sePrintErrorFunc. Instead,
this will call the internal API function. In
other words, calling seEval() with an invalid
function object is viewed as an API error instead
of a scripting error.
Fix:
The underlying API philosophy is the seEval()
should behave much like the script eval() function,
and so using a non-function object as an API
error is wrong. In COM/Nombas/jse/Isdk/Call.jsrc
function seEvalFunc(), at about line 9367 changine
this line:
this.seAPIError("Object passed as a function to seEval is not really a function.");
to
this
this.quit(TextCore.NOT_FUNCTION_VARIABLE,"");
|