Odd issue passing arrays

I have some plugin code that’s showing odd behavior.

I’m passing an array of structs into my plugin from Xojo. It worked perfectly on an older Intel iMac. However, when I tested the same exact code this morning on an M1, the result was an OutOfBounds exception.

Assuming it was something I overlooked I inserted all sorts of debugging code only to find that the function in question wasn’t even being entered. Xojo is simply gagging before it even gets to my function. This is all in the debugger, BTW. If I continue after the exception, the app crashes just where it calls the function in question.

Even more interesting - if I build the app it does not crash on the M1. It simply ‘skips’ my function entirely. Everything else works fine, but my function seems to never be called. HOWEVER, if I tell the same app to run in Rosetta, everything works perfectly. My function does its job, and all is well.

I’m left to conclude that whatever this is, it’s outside my control. Are there any known issues like this for M1 plugins?

Xojo version is 24.2.1.63299 on Ventura 13.6.9.

Also, please refrain from using this thread as advertising to sell plugins. I’m here to learn, not to consume. Thanks.

Well, could be you found an issue passing arrays.
Please create an issue and provide details for someone to reproduce.

do you know what line the exception is raised?

Maybe related to memory alignment problems of the struct contents? Xojo Bug? Xojo bad report? X86 and ARM differ on how they handle alignment.

1 Like

You know - I did have a nagging feeling that I was being naive in my handling of structs. Here’s what I did. In my plugin, I defined;

static const char *ARCGPointStructFields[] = {
    "x as CGFloat",
    "y as CGFloat",
};

…and…

`{ "ARCGPoint", REALScopeGlobal, ARCGPointStructFields, _countof(ARCGPointStructFields) }`

So now I have ARCGPoint, which I passed into my function and blithely used as a CGPoint. I hammered against this quite a lot, and it worked without issue, so I charged ahead.

In Xojo, I create an array of these as a property of a Window, and pass that into my plugin function which goes something like…

void CGCVDrawPoints( REALcontrolInstance control, REALarray structArray )
{
    RBInteger bound = REALGetArrayUBound( structArray );
    etc...

The signature for this is;

"DrawPoints( points() as ARCGPoint )"

So, again - this all works wonderfully in x86-land. My structs seem to work perfectly as CGPoints. In ARMville, not so much. Thing is, my function never even gets to the point where it reads the bounds. I even went so far as to insert a message box before that line, and nothing. It just immediately throws an out of bounds exception before even getting to my code.

I’m perfectly willing to try and submit an issue, but I’m not really sure if it rises to that level, or even quite how to frame it yet.

There was an issue using Array.Pop with Structures on ARM, but I think it was fixed in 2024r1. It sounds quite similar to what you are seeing however, maybe it’s related? See https://tracker.xojo.com/xojoinc/xojo/-/issues/75286

Edit to add:

  • it involves ARM on Mac
  • it involves an Array of Structures
  • when it fails, the OutOfBounds Exception doesn’t propagate

quite a few similarities to what you are seeing

Hmm. That does sound eerily similar. Thanks. I’ll consider filing an issue in the morning as time permits. My day job is at a newspaper. I expect it’ll be a long day.

Issue created;

https://tracker.xojo.com/xojoinc/xojo/-/issues/77762

1 Like

You should create a minimal sample causing the same symptom but removing all your real work. Your case has no content to replicate for sure and track your issue.
Upload a sample with instructions there. :wink:

1 Like

I was afraid of that. That will take some work.

Aha! The act of paring things down brought some clarity. Here we go;

void CGCVDrawPoints( REALcontrolInstance control, REALarray structArray )
{
    NSBeep();
    RBInteger bound = REALGetArrayUBound( structArray );
    ATESTPoint point = (ATESTPoint){ .x = 0.0, .y = 0.0 };
    
    // Here is where we crash!!
    REALGetArrayStructure( structArray, 0, &point );
}

Here are the relevant definitions;

typedef struct ATESTPoint {
    CGFloat x;
    CGFloat y;
} ATESTPoint;

static const char *ATESTPointStructFields[] = {
    "x as CGFloat",
    "y as CGFloat",
};

static REALstructure ATESTPointStruct = { "ATESTPoint", REALScopeGlobal, ATESTPointStructFields, 2 };

This time the behavior is slightly different. NSBeep definitely fires, so the function is being entered. However, as before, the OutOfBounds happens in ARM, but not in x86.

I’ll update the issue with some files.

1 Like

You can make a folder and put all things inside it, included sub-folders, and a readme.html or txt if necessary. Then zip it and upload it to the case.

Already done.

1 Like

For anyone who comes after, I worked around it.

I used a MemoryBlock/BinaryStream to pack doubles into a MemoryBlock rather than an array, like so…

mPoints = new MemoryBlock(0)
dim bs as new BinaryStream( mPoints )

…then in my loop…

bs.WriteDouble fx
bs.WriteDouble fy

CGFloats are pretty much always doubles now anyway. Then, I pass the MemoryBlock into my plugin as a pointer, and calculate the number of x/y pairs as MB.Size/16-1, which I pass in as my bound.

In the plugin, I can then just treat it as a normal C array of CGFloats, like so;

void CGCVDrawPointsMB( rControl, const CGPoint* points, RBInteger bound ) {

    CGPoint point = points[0];

etc...

It all works without issue, and is even slightly faster. I had wanted a cleaner solution using Xojo arrays, but this will do.