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

(prefs) FileSystemPreferences writes \0 to XML storage, causing loss of all preferences

    XMLWordPrintable

Details

    • b55
    • x86
    • linux
    • Verified

    Backports

      Description

        FULL PRODUCT VERSION :
        java version "1.8.0_25"
        Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
        Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)


        ADDITIONAL OS VERSION INFORMATION :
        Occurs on all flavours of Linux we have tested. Issue is also reproducible on any platform if you deliberately use this PreferencesFactory.

        A DESCRIPTION OF THE PROBLEM :
        XML prohibits directly storing a NUL (\u0000), even if you escape it according to XML files. The XML parser included with Java does enforce this. Sadly, the XML writing code doesn't seem to enforce it, which is what ultimately causes this issue.

        If you call prefs.put(key, "some string with \0 in it") ...

        The XML writer happily writes the \0 into the file. I think it escapes it, but as already mentioned, this is pointless. Then later, when you try to read it back in, the XML file is invalid. You get a warning on the logs about the preferences file being invalid and all your preferences are wiped.

        This *would* occur on OSX as well, but preference files on OSX are plist files and Apple's XML parser seemingly reads the \0 in as if it's valid (so they have a lucky bug, I guess. I separately reported to Apple that they shouldn't be putting that in their XML files.)


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the attached program twice.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The first time you run the program, there are no preferences stored, so you should see:

            Before putting values:
              a = null
              b = null
            After putting values (shows cached values - run again to check whether they were actually stored):
              a = 1
              b = 2�3

        The second time you run it, you should see:

            Before putting values:
              a = 1
              b = 23
            After putting values (shows cached values - run again to check whether they were actually stored):
              a = 1
              b = 23

        ACTUAL -
        The second time you run it, you actually see:

            Before putting values:
              a = null
              b = null
            After putting values (shows cached values - run again to check whether they were actually stored):
              a = 1
              b = 23

        You also get the following output on stderr:

            Dec 29, 2014 9:19:19 AM java.util.prefs.FileSystemPreferences$6 run
            WARNING: Invalid preferences format in /Users/daniel/.java/.userPrefs/com/acme/testing/prefs.xml
            Dec 29, 2014 9:19:19 AM java.util.prefs.FileSystemPreferences$6 run
            WARNING: Prefs file removed in background /Users/daniel/.java/.userPrefs/com/acme/testing/prefs.xml



        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.lang.reflect.Constructor;
        import java.util.prefs.Preferences;
        import java.util.prefs.PreferencesFactory;

        public class PreferencesTest
        {
            public static void main(String[] args) throws Exception
            {
                // Deliberately reflect so you can reproduce it on any platform.
                Constructor<? extends PreferencesFactory> constructor = Class.forName("java.util.prefs.FileSystemPreferencesFactory").asSubclass(PreferencesFactory.class).getDeclaredConstructor();
                constructor.setAccessible(true);
                PreferencesFactory factory = constructor.newInstance();

                Preferences node = factory.userRoot().node("com/acme/testing");

                System.out.println("Before putting values:");
                System.out.println(" a = " + node.get("a", null));
                System.out.println(" b = " + node.get("b", null));

                node.put("a", "1");
                node.put("b", "2\u00003");
                node.sync();

                System.out.println("After putting values (shows cached values - run again to check whether they were actually stored):");
                System.out.println(" a = " + node.get("a", null));
                System.out.println(" b = " + node.get("b", null));
            }
        }

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

        CUSTOMER SUBMITTED WORKAROUND :
        (a) Ensure that any time you read/write string values from Preferences, that you handle a potential \0.
        (b) Write your own PreferencesFactory (or find one somebody else has written) which handles all string values properly.


        Attachments

          Issue Links

            Activity

              People

                bpb Brian Burkhalter
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: