DynamicBuffer allows getting elements at negative indices. EDIT: due to safety checks being disabled

Today I experienced that trying to get an element at a negative index of a DynamicBuffer works “perfectly fine” in the sense that it doesn’t throw an exception. As far as I can see, internally the index function first calls the CheckBounds(index) function, which only seems to check for the upper bound (i.e. index cannot be equal to or greater than buffer length). So what I think happens is that it takes the memory before the buffer pointer and makes interprets it as a buffer element, essentially reading junk data as if it is a valid buffer element.

This to me seems like unintended behaviour, as I’d expect a good old IndexOutOfRangeException. Getting junk data without an error seems like something that would increase the possibility of mistakes flying under the radar and slipping into the code unnoticed.

3 Likes

Did you try it? CheckBounds casts to uint which results in everything below 0 being above int.MaxValue.
For me accessing -1 (from non-burst) gives Index -1 is out of range in DynamicBuffer of '1' Length.

1 Like

Hmmm, I see the uint cast and it should indeed work as intended.

However, that CheckBounds function doesn’t seem to get called for me at all, even when trying to access elements beyond the length (which is weird because I think I remember having gotten errors from that before).

The method does have two ConditionalAttributes for ENABLE_UNITY_COLLECTIONS_CHECKS and UNITY_DOTS_DEBUG, so I added those to the Scripting Define Symbols in the Player Settings, but I still can’t get the exception to be thrown :face_with_spiral_eyes:

So there doesn’t seem to be a bug in the DynamicBuffer’s index or CheckBounds functions, but I still don’t know why I’m not getting the errors.

I’m working from a bursted job, so I’ll check to see if that makes any difference.

I don’t think adding that define to Player Settings affects what Burst emits.
The normal method for adding safety checks to Bursted jobs is:
“Jobs > Burst > Safety Checks > On” (or “Force On”)

2 Likes

Alright, that indeed was the issue.
The exception works fine and is thrown if either called from non-burst or from burst with safety checks enabled.
Thanks everyone for helping me clear that up! :slight_smile: