Did System.arraycopy change from elements 9 to 10?

Don’t have an isolated test case yet, but unchanged code now operates differently.

This code

System.arraycopy(fpSavedSession.fpFields,1,fpSession[s].fpFields,1,fpSavedSession.fpFieldCount);

now causes the 2 input arrays to point to each other, rather than just copying the contents of the specified entries…

This did not happen until sometime after I upgraded from Elements 9 to 10 (using 10.0.0.2331)

I’m using VS2015. I backed down to RemObjects Elements - 9.3.103.2211, rebuilt in VS2015 and the problem is resolved. System.arraycopy behaves correctly.

I then reinstalled RemObjects Elements with Water - 10.0.0.2331 and reran the build in VS2015 and the problem reoccurs. Ie., System.arraycopy behaves incorrectly.

The only variable was the change in Elements version being used.

that’s a .NET api, so it’s behavior would be outside of our control?

It’s a java app, not .NET. How would changing just the compiler, not any .NET install change it anyway?

java.lang.System.arraycopy

Ah ok, same difference there though, if it’s a Java Runtime API — we just call those, we don;'t really influence what the function does… can you send me a simple jar built with both versions, so I can have a look at the binary difference?

Does installing Elements v10 change the java version that is linked and called?

No, we don’t install, update or even touch the java SDK or runtime. We just use whatever is installed. Maybe Java got updated in the interim, on its own?

As I stated: with no other changes to the machine, I reinstall Elements v9 and then System.arraycopy resumed working properly. I then installed Elements v10 again (no other changes) rebuilt the unchanged project and System.arraycopy does not work properly…

Any chance of a testcase?

Will try to find time. Unfortunately, this occurred just as I need to create a new delivery for a customer…so I must back up to Elements v9

I created the below program as a java console app in vs2015 w/ Elements v9.3.103.2211. It executed fine within vs2015 with proper handling of the arrays.

I then opened the project in Water w/Elements 10.0.0.2331 and built and ran it. It made array bb.fld point to array aa.fld. Debug output is also below.

Program:

namespace copyarraytest;

interface

uses
  java.util;

type
  fieldDef = public record
    c,r,l: Word;
  end;

  fpFieldsArrayType = array [0..100] of fieldDef;

  fpSessionType = public record
    inUse : Boolean;

    fld : fpFieldsArrayType;
    fldCnt : Integer;

  end;
  fpSessionArrayType = array [0..10] of fpSessionType;

  ConsoleApp = class
  public
    class method Main(args: array of String);
  end;

implementation
var
  aa : fpSessionArrayType;
  bb : fpSessionType;

  class method ConsoleApp.Main(args: array of String);
  begin

    aa[4].fld[0].c := 4;
    aa[4].fld[0].r := 6;
    aa[4].fld[0].l := 40;

    bb.fld[0].c := 3;
    bb.fld[0].r := 5;
    bb.fld[0].l := 39;

    writeLn('Before arraycopy');
    writeLn('aa[4].fld[0]:c,r,l ='+aa[4].fld[0].c+','+aa[4].fld[0].r+','+aa[4].fld[0].l);
    writeLn('bb.fld[0]:c,r,l    ='+bb.fld[0].c+','+bb.fld[0].r+','+bb.fld[0].l);

    System.arraycopy(aa[4].fld,0,bb.fld,0,1);

    writeLn();
    writeLn('After arraycopy');
    writeLn('aa[4].fld[0]:c,r,l ='+aa[4].fld[0].c+','+aa[4].fld[0].r+','+aa[4].fld[0].l);
    writeLn('bb.fld[0]:c,r,l    ='+bb.fld[0].c+','+bb.fld[0].r+','+bb.fld[0].l);

    writeLn();
    writeLn('After setting bb.fld[0]:c,r,l to 1,2,3');
    bb.fld[0].c := 1;
    bb.fld[0].r := 2;
    bb.fld[0].l := 3;
    writeLn('aa[4].fld[0]:c,r,l ='+aa[4].fld[0].c+','+aa[4].fld[0].r+','+aa[4].fld[0].l);
    writeLn('bb.fld[0]:c,r,l    ='+bb.fld[0].c+','+bb.fld[0].r+','+bb.fld[0].l);



    readLn();
  end;

end.

Debut output:

Listening for transport dt_socket at address: 50976
~> Process copyarraytest started
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.ConsoleApp
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.ConsoleApp
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.__Global
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.__Global
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.fpSessionType
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.fpSessionType
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.fieldDef
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: copyarraytest.fieldDef
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: com.remobjects.elements.ArrayUtils
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: com.remobjects.elements.ArrayUtils
Before arraycopy
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: com.remobjects.elements.system.UnsignedShort
~> Ignored exception of type java.lang.ClassNotFoundException on thread 0001 ()
~> Message: java.lang.ClassNotFoundException: com.remobjects.elements.system.UnsignedShort
aa[4].fld[0]:c,r,l =4,6,40
bb.fld[0]:c,r,l    =3,5,39

After arraycopy
aa[4].fld[0]:c,r,l =4,6,40
bb.fld[0]:c,r,l    =4,6,40

After setting bb.fld[0]:c,r,l to 1,2,3
aa[4].fld[0]:c,r,l =1,2,3
bb.fld[0]:c,r,l    =1,2,3
!> Fatal exception of type java.lang.NullPointerException on thread 0001 ()
!> Message: java.lang.NullPointerException
Exception in thread "main" java.lang.NullPointerException
    at copyarraytest.ConsoleApp.main(C:\arrayTest\copyarraytest\copyarraytest\Program.pas:66)


~> Process copyarraytest terminated with exit code 1

I upgraded Elements to 10.0.0.2363 and got identical results.

hrmm. It looks like you have records with arrays in them. The problem with arraycopy is that it doesn’t “know” about records, so it copies the object reference, but in those cases it should clone them (via ICloneable). We changed the record logic a bit to be sure the semantics are exactly right.

the easiest fix would be to have your own arrayCopy when dealing with structs and arrays of them.

This works perfectly with Elements v9…

So are you saying that when you “changed the the record logic a bit” this change broke the usage of arraycopy?

No. if I understand Carlo correctly, we fixed the behavior or records.

Remember that there’s no such thing as records (ie stack based structures) on there Java runtime, sport we “fake” record-like behavior, using classes with special on-copy behavior (Carlo can explain more details, of needed). There were some inconsistencies with that, that we addressed for v10.

What’s likely happening s that the old behavior you saw was a side effect of records not fully behaving as they should have, back in v9.

So the fact that it worked in v9 was an artifact of an incorrect implementation?

Are there other uses of Records that I need to investigate in moving from Elements v9 to v10?

@ck?

At any time you let the Java runtime do the work of copying a record, you need to ensure it gets cloned. (this is going to be rare though; the only thing I can think of is array copying and list.ToArray methods)

Thanks for that. You might want to put a note about this in the changelist info related to moving up to Elements v10.

1 Like