RenCloud / scs-sdk-plugin

ETS2 (Euro Truck Simulator 2) & ATS (American Truck Simulator) SDK plug-in. Telemetry data is shared via SharedMemory/Memory Mapped Files.
MIT License
191 stars 38 forks source link

System.IndexOutOfRangeException: 'Index was outside the bounds of the array.' #110

Closed Ademnn closed 1 year ago

Ademnn commented 1 year ago

Am trying to use your skd in my project but usually I get error "System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'" What's about? How to fix it?

MJRLegends commented 1 year ago

I have gotta this error a few times, look like the stacktrace for this error is

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at SCSSdkClient.SCSSdkConvert.GetFloat()
   at SCSSdkClient.SCSSdkConvert.GetTrailer()
   at SCSSdkClient.SCSSdkConvert.GetTrailers()
   at SCSSdkClient.SCSSdkConvert.Convert(Byte[] structureDataBytes)
   at SCSSdkClient.SharedMemory.Update[T]()
   at SCSSdkClient.SCSSdkTelemetry._updateTimer_Elapsed(Object sender)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.TimerQueue.FireNextTimers()

And from my testing seems to be upon loading the software using the SCSSdkClient dll upon windows startup, and im guessing im getting old data which existing in a messed up way and still in the shared memory since shutdown doesnt mean 100% shutdown anymore on windows

RenCloud commented 1 year ago

Thanks for reporting this. Also thanks for giving some testing infos and the stack trace. I'm aware of a similar bug when brakepoints are used. However, in normal "production" thet shouldn't be the case.

I have some Ideas thet I will try to test the next few days. Though the exception didn't happened for me to this day it may need some iterations to fix it or I find a way to reproduce it.

MJRLegends commented 1 year ago

Thanks for the reply, yea the point at which it gets a IndexOutOfRangeException changes sometimes as i've had the following exceptions too and i cant seem to reproduce it, apart from restarting my computer makes it sometimes happen.

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at SCSSdkClient.SCSSdkConvert.GetUint()
   at SCSSdkClient.SCSSdkConvert.GetTrailer()
   at SCSSdkClient.SCSSdkConvert.GetTrailers()
   at SCSSdkClient.SCSSdkConvert.Convert(Byte[] structureDataBytes)
   at SCSSdkClient.SharedMemory.Update[T]()
   at SCSSdkClient.SCSSdkTelemetry._updateTimer_Elapsed(Object sender)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

and

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at SCSSdkClient.SCSSdkConvert.GetSubArray(Int32 length)
   at SCSSdkClient.SCSSdkConvert.GetString(Int32 length)
   at SCSSdkClient.SCSSdkConvert.GetTrailer()
   at SCSSdkClient.SCSSdkConvert.GetTrailers()
   at SCSSdkClient.SCSSdkConvert.Convert(Byte[] structureDataBytes)
   at SCSSdkClient.SharedMemory.Update[T]()
   at SCSSdkClient.SCSSdkTelemetry._updateTimer_Elapsed(Object sender)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
MJRLegends commented 1 year ago

Let me know if you need anymore testing/debug information or any more information overall, i will be happy to help

jorensanbar commented 1 year ago

The error occurs when the offset exceeds the data[]

data[] = 32768 _offset = 32752 i = 32

_offset + 1 = 32784

Then you got a OutOfBounds data[32784]

You can catch with a if

for (var i = 0; i < length; i++) {

                if ((_offset + i) < _data.Length) //Avoid an OutOfBounds
                    ret[i] = _data[_offset + i];
            }

imagen

RenCloud commented 1 year ago

That's a possible way to avoid the problem, but not to fix the issue. I would like to try to fix/look into that first before I only avoid it. The issue is that the array is shorter than expected, the questions here are why and does it matter or can we ignore that.

Interesting there would be, if the data is in the same order/has the same offset as normal. Or in other words, is the available data still usable as usual (the already converted data is as expected).

jorensanbar commented 1 year ago

Right, that just hides the problem, we have to see if the other methods make a large or smaller offset than is really necessary by leaving these Bytes out of the final Offset (64).

RenCloud commented 1 year ago

Ok, I think I identified the problem. Seems to be a race condition... The timer seems to start another thread in any case. That means, even if another is still running. Most of the time, that is the expected behavior for that kind of timer. However, due to this, the offset is in rare situations modified by another thread, which then can lead to the reported OutOfBoundsException.

This probably happens because, wrongly for multithreading, I initialize the converting code as class in SharedMemory.cs... Most of the time it doesn't matter, but when a call needs too much time, it can then lead to the reported exception. Seems to be the same bug for debugging.

The fix for this shouldn't be too difficult. I try to get it done today or tomorrow.

MJRLegends commented 1 year ago

I've been running the changes from https://github.com/RenCloud/scs-sdk-plugin/pull/112 for a week or so now, and i can confirm as expected it does fully solve this issue without any side effects.

Thank you for fixing

RenCloud commented 1 year ago

That's nice too hear. Thanks for testing it.

RenCloud commented 1 year ago

Finally released as V. 1.12.1 and was already tested in dev.