The bug suggests that it is a regression from 2745228b14d138ea2c7f631c212440ecf7b8f453 ("ntdll: Don't use debug info presence to detect critical section global status.") but essentially the program (and more so the user script it is executing) depends on semi-random stack data. Which effectively results into random CS passed to EnterCriticalSection() from msvcrt (and it doesn't look like msvcrt is doing anything wrong). But now when Wine decides it should treat LockSemaphore as a semaphore and that is not a waitable object it spins in a tight loop outputting an error, while Windows under the same conditions throws an exception from RtlEnterCriticalSection(). I am putting a bit more details on app and script behaviour into the bug ticket.
I didn't include direct call to RtlpWaitForCriticalSection() in test because it doesn't return the status on Windows like Wine does (it is probably just a void function, the return value looks semi-random and doesn't make sense). But I verified that it doesn't hang or crash under the same conditions. If we want to make this aspect better match Windows we could maybe call an internal helper from RtlEnterCriticalSection() instead of RtlpWaitForCriticalSection() but I judged that we probably don't need to touch it until something depends on that.