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

Aliasing problem with raw memory accesses

    Details

    • Subcomponent:
    • Resolved In Build:
      b167
    • CPU:
      generic
    • OS:
      generic
    • Verification:
      Verified

      Backports

        Description

        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.

          Attachments

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

            Issue Links

              Activity

                People

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

                  Dates

                  • Created:
                    Updated:
                    Resolved: