-
-
Notifications
You must be signed in to change notification settings - Fork 311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Race condition in handling plugins packets #1665
Comments
By the way just for test, I just tried to put the lock in the game controller:
And now it doesn't misbehave anymore. |
Unfortunately while the change above definitely improves the stability of using the client with an assistant, and especially using scripts, I just stumbled upon a new issue, a deadlock, that happens when this lock is added. I'm not sure right now if it's something that the plugin does wrong or the client, but basically when in Razor Enhanced you configure 2 profiles and link them each to their character, if you start the client, and before login, in Razor Enhanced the profile selected is the wrong one, when you login and select in the client the other character, then you get a deadlock. These are the call stacks (a Worker Thread):
Main Thread:
|
I should've seen this, but locking This means that in general locking Handler it's incorrect when calling
I'll test this a bit more again, sorry for the noise. |
I first noticed this with ClassicUO 1.0.0.0, I was developing an autolooter with Razor Enhanced 0.8.2, and for debugging reasons I was printing item properties both in System messages and Overhead messages (with basically no pause).
With that script it seems I can cause several different issues in ClassicUO:
I looked a bit into this, I think the logic in ClassicUO is missing some safety checks to avoid the crash, but in theory the safety check would have to result in a disconnect anyway (because I think the packet is being read from corrupted buffer).
Few messages are printed, some are corrupted (random Japanese characters) and then a crash. This one was similar to: System.ArgumentException: Destination is too short #1618, but it was actually inside SetCapacity. It was trying to copy the old buffer over the new, but with a Span of size bigger than the old buffer.
Corrupted characters, the script end up "working" (it moves some selected items from a container to another), but then looking at the console, it's spamming "need more data" for some random but fixed packet ID.
After the whole day behind this I've been able to catch ClassicUO in this state:
While it cannot be seen for the CUO_MAIN_THREAD which instance of a circular buffer is being Dequeued from, I can see from the debugger that it's using
_pluginsBuffer
, which is also being used by that other thread, which is Enqueueing data.While there's this lock in
OnPluginRecv
:ClassicUO/src/ClassicUO.Client/Network/Plugin.cs
Lines 788 to 791 in c209bfe
There is no lock in
Update
:ClassicUO/src/ClassicUO.Client/GameController.cs
Line 368 in c209bfe
Resolution
I'm still not sure yet, to be fair I just recently digged in to the code; slapping a lock in
GameController::Update
might work, but I see that there are other accesses toPacketHandler.Handler
that are not protected, and I wonder if it's a bigger problem of having to restructure the flow of how handlers are accessed, because it's not always enough to lock the resource accessed concurrently; there might be other surrounding code that has to behave atomically.Furthermore
ParsePackets(CircularBuffer stream, bool allowPlugins)
locks the CircularBuffer itself, but I'm not sure where else is a concurrent access that it's using or might use that lock to properly synchronize access.The text was updated successfully, but these errors were encountered: