예제 #1
1
  /**
   * Converts the given value to the given NativeObject (optionally following the prototype chains).
   *
   * @param nativeObject target NativeObject
   * @param value Value to convert
   * @param prototype use the prototype chain?
   */
  public static Value toNativeObject(
      HostObject nativeObject,
      Value value,
      boolean prototype,
      Solver.SolverInterface solverInterface) {
    State state = solverInterface.getState();
    boolean bad = false;
    Set<ObjectLabel> matches = Collections.newSet();

    if (prototype) {
      // Make lookup using prototype chains
      Set<ObjectLabel> objectLabels = Collections.newSet(value.getObjectLabels());
      Set<ObjectLabel> visited = Collections.newSet();

      while (!objectLabels.isEmpty()) {
        Set<ObjectLabel> temp = Collections.newSet();
        for (ObjectLabel objectLabel : objectLabels) {
          if (!visited.contains(objectLabel)) {
            visited.add(objectLabel);
            Value prototypeValue =
                state.readInternalPrototype(java.util.Collections.singleton(objectLabel));
            prototypeValue = UnknownValueResolver.getRealValue(prototypeValue, state);

            // FIXME: Needs code review. Looks fishy to compare objects with toString().
            String nativeObjectPrototype = nativeObject.toString();
            String objectLabelPrototype = "";
            if (objectLabel.getHostObject() != null) {
              objectLabelPrototype = objectLabel.getHostObject().toString();
            }

            if (nativeObject == objectLabel.getHostObject()
                || nativeObjectPrototype.equals(objectLabelPrototype)) {
              matches.add(objectLabel);
            } else if (prototypeValue.getObjectLabels().isEmpty()) {
              bad = true;
            } else {
              temp.addAll(prototypeValue.getObjectLabels());
            }
          }
        }
        objectLabels = temp;
      }
    } else {
      // Make lookup ignoring prototype chains

      // TODO: Verify this
      for (ObjectLabel objectLabel : value.getObjectLabels()) {
        if (objectLabel.getHostObject() == nativeObject
            || (objectLabel.getHostObject() != null
                && objectLabel.getHostObject().toString().equals(nativeObject + ".prototype"))) {
          matches.add(objectLabel);
        } else {
          bad = true;
        }
      }
    }

    //        Message.Status status;
    //        if (good && bad) {
    //            status = Message.Status.MAYBE;
    //        } else if (!good && bad) {
    //            status = Message.Status.CERTAIN;
    //        } else if (good && !bad) {
    //            status = Message.Status.NONE;
    //        } else if (!good && !bad) { // equivalent to Value of Undef / a null argument
    //            // Considered a certain type error.
    //            status = Message.Status.CERTAIN;
    //        } else {
    //            throw new AnalysisException("toNativeObject: fell through cases - should not
    // happen.");
    //        }
    if (bad) {
      String message = "TypeError, argument is not of expected type: " + nativeObject;
      solverInterface
          .getMonitoring()
          .addMessage(solverInterface.getNode(), Message.Severity.HIGH, message);
    }

    return Value.makeObject(matches);
  }
예제 #2
0
  /** 11.2.2, 11.2.3, 13.2.1, and 13.2.2 'new' / function call. */
  @Override
  public void visit(CallNode n, State state) {
    if (n.getFunctionRegister()
        != AbstractNode.NO_VALUE) // old style call (where the function is given as a variable read)
    FunctionCalls.callFunction(
          new OrdinaryCallInfo(n, state) {

            @Override
            public Value getFunctionValue() {
              Value functionValue = state.readRegister(n.getFunctionRegister());
              if (n.getLiteralConstructorKind() != null) {
                // these literal invocations can not be spurious in ES5
                switch (n.getLiteralConstructorKind()) {
                  case ARRAY:
                    functionValue =
                        Value.makeObject(new ObjectLabel(ECMAScriptObjects.ARRAY, Kind.FUNCTION));
                    break;
                  case REGEXP:
                    functionValue =
                        Value.makeObject(new ObjectLabel(ECMAScriptObjects.REGEXP, Kind.FUNCTION));
                    break;
                  default:
                    throw new AnalysisException(
                        "Unhandled literal constructor type: " + n.getLiteralConstructorKind());
                }
              }
              return functionValue;
            }

            @Override
            public Set<ObjectLabel> prepareThis(State caller_state, State callee_state) {
              return UserFunctionCalls.determineThis(
                  n, caller_state, callee_state, c, n.getBaseRegister());
            }
          },
          state,
          c);
    else { // getPropertyString / getPropertyRegister - like ReadPropertyNode
      Value baseval = state.readRegister(n.getBaseRegister());
      baseval = UnknownValueResolver.getRealValue(baseval, state);
      Set<ObjectLabel> objlabels =
          baseval.getObjectLabels(); // the ReadPropertyNode has updated baseval to account for
      // ToObject
      Value propertyval;
      int propertyreg;
      if (n.isPropertyFixed()) {
        propertyreg = AbstractNode.NO_VALUE;
        propertyval = Value.makeStr(n.getPropertyString());
      } else {
        propertyreg = n.getPropertyRegister();
        propertyval = state.readRegister(propertyreg);
        propertyval = UnknownValueResolver.getRealValue(propertyval, state);
      }
      boolean maybe_undef = propertyval.isMaybeUndef();
      boolean maybe_null = propertyval.isMaybeNull();
      boolean maybe_nan = propertyval.isMaybeNaN();
      propertyval = propertyval.restrictToNotNullNotUndef().restrictToNotNaN();
      Str propertystr = Conversion.toString(propertyval, propertyreg, c);
      // read the object property value, as fixed property name or unknown property name, and
      // separately for "undefined"/"null"/"NaN"
      Map<ObjectLabel, Set<ObjectLabel>> target2this = newMap();
      List<Value> nonfunctions = newList();
      for (ObjectLabel objlabel :
          objlabels) { // find possible targets for each possible base object
        Set<ObjectLabel> singleton = singleton(objlabel);
        Value v;
        boolean read_undefined = false;
        boolean read_null = false;
        boolean read_nan = false;
        if (propertystr.isMaybeSingleStr()) {
          String propertyname = propertystr.getStr();
          v = state.readPropertyValue(singleton, propertyname);
        } else if (!propertystr.isNotStr()) {
          v = state.readPropertyValue(singleton, propertystr);
          read_undefined = propertystr.isMaybeStr("undefined");
          read_null = propertystr.isMaybeStr("null");
          read_nan = propertystr.isMaybeStr("NaN");
        } else v = Value.makeNone();
        if (maybe_undef && !read_undefined) {
          v = UnknownValueResolver.join(v, state.readPropertyValue(singleton, "undefined"), state);
        }
        if (maybe_null && !read_null) {
          v = UnknownValueResolver.join(v, state.readPropertyValue(singleton, "null"), state);
        }
        if (maybe_nan && !read_nan) {
          v = UnknownValueResolver.join(v, state.readPropertyValue(singleton, "NaN"), state);
        }
        v = UnknownValueResolver.getRealValue(v, state);

        // finally, remove all the TAJS hooks, which are spurious if accessed through a dynamic
        // property
        if (!n.isPropertyFixed()) {
          v = JSGlobal.removeTAJSSpecificFunctions(v);
        }

        for (ObjectLabel target : v.getObjectLabels()) {
          if (target.getKind() == Kind.FUNCTION) {
            addToMapSet(target2this, target, objlabel);
          } else {
            nonfunctions.add(Value.makeObject(target));
          }
        }
        if (v.isMaybePrimitive()) {
          nonfunctions.add(v.restrictToNotObject());
        }
      }
      // do calls to each target with the corresponding values of this
      for (Entry<ObjectLabel, Set<ObjectLabel>> me : target2this.entrySet()) {
        ObjectLabel target = me.getKey();
        Set<ObjectLabel> this_objs = me.getValue();
        FunctionCalls.callFunction(
            new OrdinaryCallInfo(n, state) {

              @Override
              public Value getFunctionValue() {
                return Value.makeObject(target);
              }

              @Override
              public Set<ObjectLabel> prepareThis(State caller_state, State callee_state) {
                return this_objs;
              }
            },
            state,
            c);
      }
      // also model calls to non-function values
      FunctionCalls.callFunction(
          new OrdinaryCallInfo(n, state) {

            @Override
            public Value getFunctionValue() {
              return Value.join(nonfunctions);
            }

            @Override
            public Set<ObjectLabel> prepareThis(State caller_state, State callee_state) {
              return Collections.emptySet();
            }
          },
          state,
          c);
    }
  }