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

Aliasing problem with raw memory accesses

XMLWordPrintable

    • b167
    • generic
    • generic
    • Verified

        FULL PRODUCT VERSION :
        $ java -version
        java version "1.8.0_121"
        Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
        Java HotSpot(TM) Server VM (build 25.121-b13, mixed mode)


        FULL OS VERSION :
        Linux localhost.localdomain 3.10.0-327.36.2.el7.x86_64 #1 SMP Mon Oct 10 23:08:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

        A DESCRIPTION OF THE PROBLEM :
        The attached testcase fails when run in compiled mode on 32 bit Intel Linux.

        It does NOT fail in interpreted mode (-Xint) or in compiled mode with a 64 bit VM.

        It does NOT fail on 32 bit Intel Windows.

        The testcase has taken significant effort to extract. We have a COBOL product (NTT DATA Enterprise COBOL, formerly Dell Enterprise COBOL) that translates COBOL to Java for execution and the problem originates from a customer COBOL program.

        The slightly unusual coding patterns reflect our implementation of COBOL "unsigned usage display" numerics, in which a decimal number is represented in memory using ASCII digits, i.e that characters '0', '1', ... (This also necessitates our use of 'Unsafe')

        THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

        THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Compile the code:

        $ javac Sim.java Chunk.java

        Execute 'Sim'

        $ java Sim



        EXPECTED VERSUS ACTUAL BEHAVIOR :
        $ java Sim

        Output is as follows:

        main() >
        [0000000000]
        [0000000001]
        [0000000002]
        [0000000003]
        [0000000004]
        [0000000005]
        [0000000006]
        [0000000007]
        [0000000008]
        [0000000009]
        ...
        [0000110638]
        [0000110639]
        [0000110640]
        [0000110641]
        [0000000000]
        [0000000000]
        [0000000000]
        ...
        [0000000000]
        [0000000000]
        [0000000000]
        main() <

        The output should just be an increasing integer, as can be seen by using -Xint:

        java -Xint Sim:

        main() >
        [0000000000]
        [0000000001]
        [0000000002]
        [0000000003]
        [0000000004]
        [0000000005]
        [0000000006]
        [0000000007]
        [0000000008]
        [0000000009]
        ...
        [0000198760]
        [0000198761]
        [0000198762]
        [0000198763]
        [0000198764]
        main() <

        The exact point in the failing case where the error occurs (output turns to zero) seems to vary, and I assume corresponds to when HotSpot compilation occurs

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        Sim.java:


        public class Sim {
           private final Chunk c_A1;
           private final Chunk c_A2;
           private final Chunk c_R;

           public static void main(String[] args) {
              System.out.println("main() >");

              Sim s = new Sim();
              s.go();

              System.out.println("main() <");
           }

           public Sim() {
              Chunk r_0 = new Chunk(64);
              c_A1 = r_0.slice(0, 11);
              c_A2 = r_0.slice(11, 11);
              c_R = r_0.slice(22, 19);
           }

           private void go() {
              c_A1.fillSmall(0, 11, (byte)0x30);
              for (long i = 0; i < 198765L; i++) {
                 c_A2.put_Long_DU(0, 11, i );
                 c_R.fillSmall(9, 10, (byte)0x30);
                 c_R.put_Long_DU(9, 10, c_R.get_DU_Long(9, 10) + c_A2.get_DU_Long(0, 11));
                 c_R.put_Long_DU(9, 10, c_R.get_DU_Long(9, 10) + c_A1.get_DU_Long(0, 11));

                 printR();
              }
           }

           private void printR() {
              final byte[] ba = c_R.getAsByteArray(9, 10);
              final String s = new String(ba);
              System.out.println("[" + s + "]");
           }
        }



        Chunk.java:


        import java.lang.reflect.Field;
        import sun.misc.Unsafe;

        public class Chunk {

           private static final Unsafe UNSAFE;

           private final long baseAddress;
           private final int length;

            static {
               Unsafe u = null;
               try {
                  final Class<Unsafe> uc = Unsafe.class;
                  final Field field = uc.getDeclaredField("theUnsafe");
                  field.setAccessible(true);
                  u = (Unsafe) field.get(uc);
               } catch (NoSuchFieldException | IllegalAccessException | RuntimeException ex) {
                  ex.printStackTrace();
               }
               UNSAFE = u;
            }

           public Chunk(int length) {
              baseAddress = UNSAFE.allocateMemory(length);
              this.length = length;
           }

           public final long getBaseAddress() {
              return baseAddress;
           }

           public final int getLength() {
              return length;
           }

           protected Chunk(Chunk oc, int op, int ol) {
              baseAddress = oc.getBaseAddress() + op;

              if (oc.getLength() == -1) {
                 length = -1;
              } else {
                 length = Math.min(ol, oc.getLength() - op);
              }
           }

           public Chunk slice(int p, int l) {
              Chunk o = new Chunk(this, p, l);
              return o;
           }

           public final void fillSmall(int tp, int tl, byte b) {
              long p = baseAddress + tp;
              for (int i = 0; i < tl; i++) {
                 UNSAFE.putByte(p++, b);
              }
           }

           public void put_Long_DU(int p, int d, long v) {

              long a = baseAddress + p;

              for (int i = d - 1; i >= 0; i--) {
                 long b = (v % 10) + 0x30;
                 UNSAFE.putByte(a + i, (byte) b);
                 v /= 10;
              }
           }

           public long get_DU_Long(int p, int l) {
              long a = baseAddress + p;

              long ret = 0;
              for (int i = 0; i < l; i++) {
                 final int b = UNSAFE.getByte(a++);
                 ret *= 10;
                 ret += b & 0x0f;
              }

              return ret;
           }

           public byte[] getAsByteArray(int p, int l) {
              byte[] ret = new byte[l];
              long a = baseAddress + p;
              for (int i = 0; i < l; i++) {
                 ret[i] = UNSAFE.getByte(a++);
              }
              return ret;
           }

        }






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

        CUSTOMER SUBMITTED WORKAROUND :
        End customer has had to change their original COBOL program to avoid generating the pattern that causes this issue. They have had to do this in multiple programs.

          1. Chunk.java
            2 kB
          2. Chunk2.java
            2 kB
          3. Sim.java
            1.0 kB
          4. Sim2.java
            1 kB

              iveresov Igor Veresov
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

                Created:
                Updated:
                Resolved: