Scoping issue with passed functions

Dec 31, 2009 at 8:15 PM

I ran into an issue in Jint in the way it evaluates scopes to lookup identifiers when executing a function.  Let's say I have a simplistic script like this:

function foo(){
   var x = "right";
   function bar()    {
       alert(x);
   } 
   callFunc(bar);
}

function callFunc( f ){
   var x = "wrong";
   f(); 
}

foo();

The scoping rules say that when I run this, I should see "right" alerted (this is confirmed by running this script in JScript.dll.)  However, when I run this in Jint, what I actually see is "wrong".  The issue is that when Jint evaluates f() (inside callFunc) it does a lookup for x by simply walking up the scope chain.  This results in it finding the x defined in callFunc instead of the one defined in foo().  This leads to all sorts of issues and incorrect execution of script.

I was able to code up a partial fix for this by adding a new property to JsFunction called DeclaredScopes.  Whenever a new JsFunction is created (which happens in several locations), I add the Scopes list at that time to it.  Then, in ExecutionVisitor.CallFunction, I Enter the entire list of DeclaredScopes before I enter the function scope:

    foreach (JsDictionaryObject scope in function.DeclaredScopes)
    {
        EnterScope(scope);
    }
           
    EnterScope(function.Scope);
    EnterScope(functionScope);

I believe this partially but not completely fixes the issue.  Functions now find the right members, BUT if the only defined identifier is in the stack (but not in the DeclaredScopes) the function will find it when I believe it should find nothing.

Jan 1, 2010 at 9:47 PM

Actually, this bug, is due to a lack of code factorisation. If you compare Visit(FunctionExpression) and Visit(FunctionDeclarationStatement), you would see a missing block. I have just corrected it adding your test to unit tests.

If you take the latest version on SVN, you should see this bug solved.