Revision: 5578
Author:   [email protected]
Date:     Mon Aug 26 17:08:41 2013 UTC
Log:      Work around infinite recursion in scanner on Chrome.
https://codereview.appspot.com/13202043

This is a quick fix for
<https://code.google.com/p/google-caja/issues/detail?id=1848>
which should be replaced with something more principled once we figure
out what that is.

* Do not PLAIN_CALL any getter with a property named "stack".
* Add a limit for depth of traversal. (This will cause the test to fail
  rather than run out of time/memory, in the event of any future similar
  problems.)

Supporting changes:
* Move all definitions in test-scan-guest relating to Error to one place
  and use new Ref definition style.

[email protected]

http://code.google.com/p/google-caja/source/detail?r=5578

Modified:
 /trunk/tests/com/google/caja/plugin/test-scan-core.js
 /trunk/tests/com/google/caja/plugin/test-scan-guest.js

=======================================
--- /trunk/tests/com/google/caja/plugin/test-scan-core.js Fri Aug 23 17:58:39 2013 UTC +++ /trunk/tests/com/google/caja/plugin/test-scan-core.js Mon Aug 26 17:08:41 2013 UTC
@@ -421,6 +421,7 @@
      *
      * @param object The object of interest.
      * @param path A textual short description of how we got the object.
+ * @param depth Count of sequential operations performed to get the object. * @param getSelfC Returns the context of something to use instead of the * object on methods (i.e. an instance if the object is a prototype).
      * @param getThisArgC Ditto but for the thisArg for invoking the object
@@ -430,7 +431,8 @@
* attempting to obtain an instance of a not-actually-a-constructor. * @param getProgram A thunk for program source which returns the object.
      */
-    function makeContext(object, path, getSelfC, getThisArgC, getProgram) {
+    function makeContext(object, path, depth, getSelfC, getThisArgC,
+        getProgram) {
       var context;
       var prefix = path === '' ? '' : path + '.';
       if (getSelfC === 'self') {
@@ -449,6 +451,7 @@
         },
         get: function() { return object; },
         getPath: function() { return path; },
+        getDepth: function() { return depth; },
         getter: function(name, getter) {
           function getterProgram() {
             return 'Object.getOwnPropertyDescriptor(' +
@@ -460,6 +463,7 @@
           return makeContext(
               getter,
               prefix + 'get ' + name,
+              depth + 1,
               'self',
               getSelfC,
               getterProgram);
@@ -468,6 +472,7 @@
           return makeContext(
               setter,
               prefix + 'set ' + name,
+              depth + 1,
               'self',
               getSelfC,
               function() {
@@ -481,12 +486,13 @@
           if (p === 'prototype') {
// When invoking methods on a prototype, use an instance of this
             // ctor instead as 'this'.
-            var protoctx = makeContext(pval, subpath,
+            var protoctx = makeContext(pval, subpath, depth + 1,
                 function() {
                   var selfC = getSelfC();
                   return makeContext(
                       obtainInstance(selfC.get(), selfC),
                       path + '<instance>',
+                      depth + 1,
                       'self',
                       function() { return noThisContext; },
                       protoctx,
@@ -503,6 +509,7 @@
             return makeContext(
                 pval,
                 subpath,
+                depth + 1,
                 getSelfC,
                 function() { return noThisContext; },
                 function() {
@@ -512,6 +519,7 @@
             return makeContext(
                 pval,
                 subpath,
+                depth + 1,
                 'self',
                 getSelfC,
                 function() {
@@ -528,6 +536,7 @@
           return makeContext(
               ival,
               path + argstr + (thrown ? ' thrown ' : ''),
+              depth + 1,
               'self',
               getSelfC,
               function() {
@@ -552,6 +561,7 @@
         undefined,
         '<noThis>',
         'self',
+        0,
         function() { return noThisContext; },
         function() { return 'undefined'; });

@@ -560,6 +570,7 @@
         return makeContext(
             o,
             path,
+            0,
             'self',
             function() { return noThisContext; },
             function() { return code; });
@@ -663,6 +674,11 @@
           log(path, ' FILTERED\n');
           return;
         }
+
+        if (context.getDepth() > 16) {
+          noteGap('Depth limit reached', context);
+          return;
+        }

         // deduplication and logging
         var seenName = seenTable.get(object);
@@ -706,7 +722,12 @@
           var didSomeCall = false;
           var didNonThrowingCall = false;

-          var shouldPlainCall = isNativeFunction(object);
+ // TODO(kpreid): the '.get stack' rule is a misplaced kludge which + // should at least live in the caller. It is needed to avoid infinite
+          // descent. See
+          // <https://code.google.com/p/google-caja/issues/detail?id=1848>.
+          var shouldPlainCall = isNativeFunction(object) &&
+              !(/\.get stack/.test(path));
           var didPlainCall = false;

           var doInvocation = function(tuple) {
=======================================
--- /trunk/tests/com/google/caja/plugin/test-scan-guest.js Fri Aug 23 17:58:39 2013 UTC +++ /trunk/tests/com/google/caja/plugin/test-scan-guest.js Mon Aug 26 17:08:41 2013 UTC
@@ -705,14 +705,25 @@
     argsByAnyFrame('String.prototype.trimLeft', genNoArgMethod);
     argsByAnyFrame('String.prototype.trimRight', genNoArgMethod);

-    var genErrorConstruct = genAllCall(genString);
-    argsByAnyFrame('Error', genErrorConstruct);
-    argsByAnyFrame('EvalError', genErrorConstruct);
-    argsByAnyFrame('RangeError', genErrorConstruct);
-    argsByAnyFrame('ReferenceError', genErrorConstruct);
-    argsByAnyFrame('SyntaxError', genErrorConstruct);
-    argsByAnyFrame('TypeError', genErrorConstruct);
-    argsByAnyFrame('URIError', genErrorConstruct);
+    // Error objects
+    functionArgs.set(Ref.all(
+            RefAnyFrame('Error'),
+            RefAnyFrame('EvalError'),
+            RefAnyFrame('RangeError'),
+            RefAnyFrame('ReferenceError'),
+            RefAnyFrame('SyntaxError'),
+            RefAnyFrame('TypeError'),
+            RefAnyFrame('URIError')),
+        genAllCall(genString));
+    expectedUnfrozen.mark(Ref.all(
+        Ref.ctor(Error),
+        Ref.ctor(tamingEnv.Error)));
+    // fresh-on-every-instance getter, on at least Chrome 31.0.1609.0
+    expectedUnfrozen.mark(Ref.all(
+        Ref.path('.get stack'),
+        Ref.path('.set stack'),
+        Ref.path('.get stack.prototype'),
+        Ref.path('.set stack.prototype')));

     argsByIdentity(cajaVM.allKeys, genMethod(genJSONValue));
     function cweF1(ejector) {
@@ -1043,7 +1054,6 @@
     argsByProp('getBoundingClientRect', freshResult(genNoArgMethod));
     argsByProp('updateStyle', genNoArgMethod);
     argsByProp('getPropertyValue', genMethod(genCSSPropertyName));
-    argsByProp('set stack', G.none);
argsByProp('getContext', genMethod(G.value(undefined, null, 'bogus', '2d',
         'webgl', 'experimental-webgl')));
     argsByProp('querySelector', genMethod(genCSSSelector));
@@ -1202,7 +1212,6 @@
     argsByProp('stopPropagation', G.none);
     argsByProp('preventDefault', G.none);

-    var tamingFrameError = tamingEnv.Error;
     expectedUnfrozen.addSpecialCase(function(context) {
       var object = context.get();
       var path = context.getPath();
@@ -1243,8 +1252,6 @@
     expectedUnfrozen.setByConstructor(Node, true);
     assertTrue(location.constructor !== Object);
     expectedUnfrozen.setByConstructor(location.constructor, true);
-    expectedUnfrozen.setByConstructor(Error, true);
-    expectedUnfrozen.setByConstructor(tamingEnv.Error, true);
     // these types can't be coherently exported due to ArrayLike gimmick
     //expectedUnfrozen.setByConstructor(NodeList, true);
     //expectedUnfrozen.setByConstructor(NamedNodeMap, true);

--

--- You received this message because you are subscribed to the Google Groups "Google Caja Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to