-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
ffi/extension_methods_test
went from Pass -> Crash on vm-win-release-ia32
#59779
Comments
@dcharkes I've looked into this, and it seems to be related to the use of I can also reproduce the crash with this code: void testCompoundRefWithFinalizer() {
final ptr = calloc<Uint8>();
final typedData = ptr.asTypedList(1, finalizer: calloc.nativeFree);
// final vec4 = Struct.create<Vec4>();
// vec4
// ..x = 1.2
// ..y = 3.4
// ..z = 5.6
// ..w = 7.8;
// final result = twiddleVec4Components(vec4);
// Expect.equals(3.4, result.x);
// Expect.equals(5.6, result.y);
// Expect.equals(7.8, result.z);
// Expect.equals(1.2, result.w);
} Here's the output:
|
Does it reliably reproduce, or flakily? It seems like this is an existing bug, but it's suspicious it started occurring from your CL. Your CL shouldn't have changed how existing code is executed. The best way to investigate this is to build a Debug build, repro it there and run
|
Yes, it reproduces reliably every time I run the test.
I'll try to do this, thanks. |
@dcharkes I've managed to capture the exception. Here's the screenshot: Please let me know if you need more information. I've used the following code to reproduce the crash: import 'dart:ffi';
import 'package:ffi/ffi.dart';
void main() {
final p = calloc<Uint8>();
final typedData = p.asTypedList(1, finalizer: calloc.nativeFree);
} |
The stack 🙏 |
I should also mention the original program I've used to debug was: import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
void main() async {
sleep(Duration(seconds: 30));
print('start');
final p = calloc<Uint8>();
final typedData = p.asTypedList(1, finalizer: calloc.nativeFree);
print('done');
} I've used |
An access violation while trying to unlock a mutex, that sounds like the memory of the mutex itself has been released already. And it's doing so while trying to process a message in the message handler. If a mutex memory is no longer accessible, then something owning that mutex must have been freed, which is then the (Why that behavior would be different on ia32 compared to other architectures though?) |
See logs
|
Okay, so the So, I'm pretty convinced something is trying to post a message to the You're seeing all corners of the VM now. 😄 |
See logs
😆 |
I run the program again but this time also attached the VS debugger and got:
From the above logs, the |
Nice spotting! That could mean that if (FLAG_trace_finalizers) {
THR_Print(
"%s: Running native finalizer %p callback %p "
"with token %p\n",
trace_context, ptr()->untag(), callback, peer);
}
entry.set_token(entry);
callback(peer);
// Add if(trace) Print( ... to verify that we don't reach this. And then we can triage why it's not executable. It should be final Pointer<NativeFunction<WinCoTaskMemFreeNative>> winCoTaskMemFreePointer =
ole32lib.lookup('CoTaskMemFree'); Hm, but it should be that the "token" is the parameter passed to the free function. So that should simply be |
Yes, it crashes before reaching the print I added. The weird thing is the addresses of the pointers doesn't match the addresses in the logs:
This was the code I used: import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
final finalizer = calloc.nativeFree;
void main() {
// sleep(Duration(seconds: 10));
final p = calloc<Uint8>();
print('p: $p');
print('finalizer: $finalizer');
final typedData = p.asTypedList(1, finalizer: finalizer);
print('done');
} Another thing I've tried is that instead of using
This was the code I used: import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
final finalizer = calloc.nativeFree;
class C implements Finalizable {
C(this.p) {
_finalizer.attach(this, p.cast());
}
static final _finalizer = NativeFinalizer(finalizer);
final Pointer<Uint8> p;
}
void main() {
// sleep(Duration(seconds: 10));
final p = calloc<Uint8>();
print('p: $p');
final c = C(p);
print('finalizer: $finalizer');
// final typedData = p.asTypedList(1, finalizer: finalizer);
print('done');
} Next, I tried setting the
I'm so confused. 😆 Edit: I can also reproduce this in 9f82b8595dce2d269cf2fe32f313360d53a51192 which was the last commit before my CL merged. |
Ah, it might be that If the error occurs with
Interesting, so it's not the finalizer callback that's crashing.
But a fully symbolized stack trace! ❤️ It's is the same type of error, an access violation. So we're trying to access something that already has been freed. It's not immediately obvious what we're accessing that's free. The
You can try some very old commits to see how long it's been there. You can give
(I don't think I've ever used P.S. I love your rigor! ❤️ Teamwork makes the dreamwork! |
There's a test in void testAsTypedList() {
const length = 10;
final ptr = calloc(length, sizeOf<Int16>()).cast<Int16>();
final typedList = ptr.asTypedList(length, finalizer: freePointer);
print(typedList);
}
@Native<Pointer<Void> Function(IntPtr num, IntPtr size)>(isLeaf: true)
external Pointer<Void> calloc(int num, int size);
final freePointer = DynamicLibrary.process()
.lookup<NativeFunction<Void Function(Pointer<Void>)>>('free'); |
Actually, if the test was consistently succeeding on the bots before on all Dart versions, and now it's consistently failing. It could be that the Windows bots got updated yesterday (2024-12-19) with a newer Windows version (cc @athomas Did we update Windows bots yesterday?). And if it's failing for you locally, you probably have the same Windows version as the bots. That means trying very old commits will probably reproduce the issue for you locally, and also on the bots if we revert.
That could be. That would be consistent with a Windows update changing the behavior of (It's not consistent with getting access violations on two places in VM code when looking at the stack traces. Are the stack traces consistent on multiple runs in the debugger? And the two different VM crashes are both an access violation, so they do point to the same type of issue.)
I am no Windows expert. I would refer to the experts doing |
Exactly. I’ve confirmed that the addresses indeed match inside the
It seems that way. I set some breakpoints and observed that the finalizer callbacks were executed without any issues. However, the crash always occurs right after the surrounding function completes execution -- in the case of
It seems the
Just to clarify: the failing test is the one I added in my CL, which uses For reference, I’m using Windows 11 Insider Preview Build 22635.4445, while the logs in the setup_build step suggest the Windows bots are using Windows-10-19045.2006.
Allocating and freeing pointers with
Yes, they are entirely consistent across runs.
Haha, I wouldn’t call myself a Windows expert, but I’ll take that as a compliment! 😄 As for my thoughts on this issue: since there haven’t been any reports from users experiencing this crash, and with IA32 support being phased out in Dart 3.8, it might not be worth investigating this further. Thanks so much for looking into this with me, Daco. I’ve learned a lot along the way. 🙏 |
Yeah, that sounds about right. That would explain why we got two different access violations both on
Agreed 👍
You're welcome! And thanks for your contributions (both in the SDK and |
https://ci.chromium.org/ui/p/dart/builders/ci.sandbox/vm-win-release-ia32/602/overview
@dcharkes
The text was updated successfully, but these errors were encountered: