Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8044000

Access to undefined property yields "null" instead of "undefined"

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 8u20, 9
    • Fix Version/s: 9
    • Component/s: core-libs
    • Labels:
    • Subcomponent:
    • Resolved In Build:
      b15
    • CPU:
      x86_64
    • OS:
      windows_7

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.9.0-ea"
        Java(TM) SE Runtime Environment (build 1.9.0-ea-b13)
        Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b13, mixed mode)

        java version "1.8.0_20-ea"
        Java(TM) SE Runtime Environment (build 1.8.0_20-ea-b11)
        Java HotSpot(TM) 64-Bit Server VM (build 25.20-b10, mixed mode)

        java version "1.8.0_20-ea"
        Java(TM) SE Runtime Environment (build 1.8.0_20-ea-b15)
        Java HotSpot(TM) 64-Bit Server VM (build 25.20-b15, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 6.1.7601]

        A DESCRIPTION OF THE PROBLEM :
        A small conversion script of mine is failing to correctly handle script objects after they have been transferred to a different Global. The immediate cause of this is the fact that access to undefined properties / functions does not return "undefined" as they should, instead returning null when the conversion script is run against the object in the second Global. This incorrectly triggers a conditional block in the conversion script that is designed to handle String-like values.

        This issue manifests itself in a very peculiar constellation for which the causality escapes my understanding.
        - a prior execution (in an unrelated Global) has to include an instance of a Map as the value of a property of the script object to be converted
        - the conversion script has to contain a conditional block that handles conversion of native JavaScript objects into Map instances

        If either of these parameters is altered (e.g. the Map instance in the prior execution replace by a simple Object) the issue does not occur.

        The test case works correctly when run in JDK 1.8.0_05

        REGRESSION. Last worked in version 8

        ADDITIONAL REGRESSION INFORMATION:
        java version "1.8.0_05"
        Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
        Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Execute the test case with assertions enabled (-ea)

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The program completes without failing any of the assertions.
        ACTUAL -
        The pogram fails the second to last of the assertion. The result of the conversion is an instance of java.lang.String instead of the expected java.util.Map

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Exception in thread "main" java.lang.AssertionError
        at Test2.main(Test2.java:52)


        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.util.Collections;
        import java.util.Map;

        import javax.script.Bindings;
        import javax.script.ScriptEngine;
        import javax.script.ScriptEngineManager;

        public class Test2
        {

            private static final String TEST_SCRIPT =
                    "function convert(o) {" +
                        "var b = o, c, d, e, f, g;" +
                        // test for native or Java String
                        "if (typeof o === 'string' || o.toUpperCase!== undefined) {" +
                            "c = Java.type('java.lang.String');" +
                            "b = new c(o);" +
                        "} else if (typeof o === 'object') {" +
                            "c = Java.type('java.util.HashMap');" +
                            "b = new c();" +
                            "for (d in o) { b.put(convert(d), convert(o[d])); }" +
                        "} return b; }" +
                    "javaObj = convert(nashornObj);";

            public static void main(final String[] args) throws Exception
            {
                final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");

                // construct object with reference to a Java Map (this somehow triggers the assert to fail in the end)
                // Note: replacing map with Object => everything works fine again
                final Bindings globalBindings = engine.createBindings();
                globalBindings.put("map", Collections.<String, Object> emptyMap());
                engine.eval("nashornObj = { test: map };", globalBindings);

                engine.eval(TEST_SCRIPT, globalBindings);
                assert !(globalBindings.get("javaObj") instanceof String);
                assert globalBindings.get("javaObj") instanceof Map<?, ?>;

                // construct object in new Global
                final Bindings originalBindings = engine.createBindings();
                engine.eval("nashornObj = { test: 12 }", originalBindings);
                // show that it works in original Global
                engine.eval(TEST_SCRIPT, originalBindings);
                assert !(originalBindings.get("javaObj") instanceof String);
                assert originalBindings.get("javaObj") instanceof Map<?, ?>;

                // transfer to a different Global
                final Bindings secondaryBindings = engine.createBindings();
                secondaryBindings.put("nashornObj", originalBindings.get("nashornObj"));
                // it should also work in different Global, but doesn't
                engine.eval(TEST_SCRIPT, secondaryBindings);
                assert !(secondaryBindings.get("javaObj") instanceof String);
                assert secondaryBindings.get("javaObj") instanceof Map<?, ?>;
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        The primary workaround for the test case is to always combine checks against undefined with checks against null, even though null is 100 % certain to either undefined or a function reference.

          Attachments

            Issue Links

              Activity

                People

                Assignee:
                sundar Sundararajan Athijegannathan
                Reporter:
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                  Dates

                  Created:
                  Updated:
                  Resolved: