Repository: flutter
Issue: Segfault on engine deinitialize in custom embedder
Labels: c: crash,engine,e: embedder,platform-linux,a: desktop,P2,team-engine,triaged-engine

I recently started helping with maintenance on the go-flutter-desktop embedder, and have come across an issue (go-flutter-desktop/go-flutter#634) that I can't reproduce in the official Linux embedder, but can't find a clear cause for in the go-flutter-desktop codebase.

The issue occurred in Flutter stable 2.5.x, Flutter beta 2.8, and the new 2.8.

### Symptom
If an application is displaying an image and has spawned additional isolates, a segfault occurs on the io.flutter.io thread, before FlutterEngineShutdown returns on the embedder's main thread.

### Minimal example

[See example repository](https://github.com/jslater89/go-flutter-desktop-repro).

If not on Linux x64, [install hover](https://github.com/go-flutter-desktop/hover#install). The repository contains a prebuilt hover executable for Linux x64.

```
hover run
# hover run builds an executable in e.g. go/build/outputs/linux-debug_unopt
```

If you hit the Exit button before the image displays, the app exits normally. If you hit it after the image displays, the app segfaults on exit.

Comment out either the Container with key bg1 or the call to `compute` in `initState`, and the issue goes away.

### Investigation/Speculation
There's a whole lot more of this in the linked issue, but here's the short version, starting with the stack trace from the segfault, but I'll reproduce the current state of my knowledge here.

<details><summary>io.flutter.io segfault</summary>

```
#0  sk_sp<GrGLCaps>::get (this=0x58) at ../../third_party/skia/include/core/SkRefCnt.h:298
#1  0x00007ffff726c139 in GrGLContextInfo::caps (this=0x0) at ../../third_party/skia/src/gpu/gl/GrGLContext.h:46
#2  0x00007ffff726bd74 in GrGLGpu::glCaps (this=0x7fffc40df250) at ../../third_party/skia/src/gpu/gl/GrGLGpu.h:50
#3  0x00007ffff729a28d in GrGLGpu::deleteSync (this=0x7fffc40df250, sync=0x1) at ../../third_party/skia/src/gpu/gl/GrGLGpu.cpp:4044
#4  0x00007ffff72bc20c in GrGLSemaphore::~GrGLSemaphore (this=0x7fffc40e2d00) at ../../third_party/skia/src/gpu/gl/GrGLSemaphore.cpp:18
#5  0x00007ffff72bc239 in GrGLSemaphore::~GrGLSemaphore (this=0x7fffc40e2d00) at ../../third_party/skia/src/gpu/gl/GrGLSemaphore.cpp:16
#6  0x00007ffff6f11c2c in std::__1::default_delete<GrSemaphore>::operator() (this=0x7fffc40e5f70, __ptr=0x7fffc40e2d00) at ../../third_party/libcxx/include/memory:2338
#7  0x00007ffff6f11bec in std::__1::unique_ptr<GrSemaphore, std::__1::default_delete<GrSemaphore> >::reset (this=0x7fffc40e5f70, __p=0x0) at ../../third_party/libcxx/include/memory:2593
#8  0x00007ffff6f113e9 in std::__1::unique_ptr<GrSemaphore, std::__1::default_delete<GrSemaphore> >::~unique_ptr (this=0x7fffc40e5f70) at ../../third_party/libcxx/include/memory:2547
#9  0x00007ffff6f0e2d3 in GrBackendTextureImageGenerator::RefHelper::~RefHelper (this=0x7fffc40e5f10) at ../../third_party/skia/src/gpu/GrBackendTextureImageGenerator.cpp:41
#10 0x00007ffff6f1157d in SkNVRefCnt<GrBackendTextureImageGenerator::RefHelper>::unref (this=0x7fffc40e5f10) at ../../third_party/skia/include/core/SkRefCnt.h:180
#11 0x00007ffff6f0e84b in GrBackendTextureImageGenerator::~GrBackendTextureImageGenerator (this=0xc7bc70 <kDartIsolateSnapshotData+794128>) at ../../third_party/skia/src/gpu/GrBackendTextureImageGenerator.cpp:81
#12 0x00007ffff6f0e899 in GrBackendTextureImageGenerator::~GrBackendTextureImageGenerator (this=0xc7bc70 <kDartIsolateSnapshotData+794128>) at ../../third_party/skia/src/gpu/GrBackendTextureImageGenerator.cpp:80
#13 0x00007ffff6a4e54c in std::__1::default_delete<SkImageGenerator>::operator() (this=0x7fffc40ebfc8, __ptr=0xc7bc70 <kDartIsolateSnapshotData+794128>) at ../../third_party/libcxx/include/memory:2338
#14 0x00007ffff6a4e4cc in std::__1::unique_ptr<SkImageGenerator, std::__1::default_delete<SkImageGenerator> >::reset (this=0x7fffc40ebfc8, __p=0x0) at ../../third_party/libcxx/include/memory:2593
#15 0x00007ffff6a4e2b9 in std::__1::unique_ptr<SkImageGenerator, std::__1::default_delete<SkImageGenerator> >::~unique_ptr (this=0x7fffc40ebfc8) at ../../third_party/libcxx/include/memory:2547
#16 0x00007ffff6c1e96a in SharedGenerator::~SharedGenerator (this=0x7fffc40ebfc0) at ../../third_party/skia/src/image/SkImage_Lazy.cpp:38
#17 0x00007ffff6c1e91d in SkNVRefCnt<SharedGenerator>::unref (this=0x7fffc40ebfc0) at ../../third_party/skia/include/core/SkRefCnt.h:180
#18 0x00007ffff6c1d8b0 in SkSafeUnref<SharedGenerator> (obj=0x7fffc40ebfc0) at ../../third_party/skia/include/core/SkRefCnt.h:150
#19 0x00007ffff6c1dd7c in sk_sp<SharedGenerator>::~sk_sp (this=0x7fffc40ec020) at ../../third_party/skia/include/core/SkRefCnt.h:251
#20 0x00007ffff6c1e352 in SkImage_Lazy::~SkImage_Lazy (this=0x7fffc40ebff0) at ../../third_party/skia/src/image/SkImage_Lazy.h:21
#21 0x00007ffff6c1e389 in SkImage_Lazy::~SkImage_Lazy (this=0x7fffc40ebff0) at ../../third_party/skia/src/image/SkImage_Lazy.h:21
#22 0x00007ffff696b45f in SkRefCntBase::internal_dispose (this=0x7fffc40ebff0) at ../../third_party/skia/include/core/SkRefCnt.h:98
#23 0x00007ffff62f49a0 in SkRefCntBase::unref (this=0x7fffc40ebff0) at ../../third_party/skia/include/core/SkRefCnt.h:77
#24 0x00007ffff6348d40 in SkSafeUnref<SkImage> (obj=0x7fffc40ebff0) at ../../third_party/skia/include/core/SkRefCnt.h:150
#25 0x00007ffff6348d8c in sk_sp<SkImage>::~sk_sp (this=0x7fffcc4d8470) at ../../third_party/skia/include/core/SkRefCnt.h:251
#26 0x00007ffff7499829 in flutter::DrawImageRectOp::~DrawImageRectOp (this=0x7fffcc4d8430) at ../../flutter/flow/display_list.cc:576
#27 0x00007ffff7483510 in flutter::DisposeOps (ptr=0x7fffcc4d8478 "", end=0x7fffcc4d8530 "") at ../../flutter/flow/display_list.cc:907
#28 0x00007ffff7483207 in flutter::DisplayList::~DisplayList (this=0x7fffcc2de470) at ../../flutter/flow/display_list.cc:1022
#29 0x00007ffff7483669 in flutter::DisplayList::~DisplayList (this=0x7fffcc2de470) at ../../flutter/flow/display_list.cc:1020
#30 0x00007ffff696b45f in SkRefCntBase::internal_dispose (this=0x7fffcc2de470) at ../../third_party/skia/include/core/SkRefCnt.h:98
#31 0x00007ffff62f49a0 in SkRefCntBase::unref (this=0x7fffcc2de470) at ../../third_party/skia/include/core/SkRefCnt.h:77
#32 0x00007ffff74cc80f in flutter::SkiaUnrefQueue::Drain (this=0x7fffc40e19e0) at ../../flutter/flow/skia_gpu_object.cc:44
#33 0x00007ffff74cdd3d in flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0::operator()() const (this=0x7fffc4000ec8) at ../../flutter/flow/skia_gpu_object.cc:30
#34 0x00007ffff74cdcfd in std::__1::__invoke<flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0&> (__f=...) at ../../third_party/libcxx/include/type_traits:3530
#35 0x00007ffff74cdcad in std::__1::__invoke_void_return_wrapper<void>::__call<flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0&>(flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0&) (__args=...) at ../../third_party/libcxx/include/__functional_base:348
#36 0x00007ffff74cdc7d in std::__1::__function::__alloc_func<flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0, std::__1::allocator<flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0>, void ()>::operator()() (this=0x7fffc4000ec8)
    at ../../third_party/libcxx/include/functional:1533
#37 0x00007ffff74ccfd9 in std::__1::__function::__func<flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0, std::__1::allocator<flutter::SkiaUnrefQueue::Unref(SkRefCnt*)::$_0>, void ()>::operator()() (this=0x7fffc4000ec0)
    at ../../third_party/libcxx/include/functional:1707
#38 0x00007ffff62ff8d2 in std::__1::__function::__value_func<void ()>::operator()() const (this=0x7fffd62c0cf0) at ../../third_party/libcxx/include/functional:1860
#39 0x00007ffff62ff875 in std::__1::function<void ()>::operator()() const (this=0x7fffd62c0cf0) at ../../third_party/libcxx/include/functional:2419
#40 0x00007ffff63e8ec4 in fml::MessageLoopImpl::FlushTasks (this=0x7fffc4000b80, type=fml::FlushType::kAll) at ../../flutter/fml/message_loop_impl.cc:130
#41 0x00007ffff63e8d9a in fml::MessageLoopImpl::RunExpiredTasksNow (this=0x7fffc4000b80) at ../../flutter/fml/message_loop_impl.cc:143
#42 0x00007ffff64032ba in fml::MessageLoopLinux::OnEventFired (this=0x7fffc4000b80) at ../../flutter/fml/platform/linux/message_loop_linux.cc:89
#43 0x00007ffff640326c in fml::MessageLoopLinux::Run (this=0x7fffc4000b80) at ../../flutter/fml/platform/linux/message_loop_linux.cc:70
#44 0x00007ffff63e8d39 in fml::MessageLoopImpl::DoRun (this=0x7fffc4000b80) at ../../flutter/fml/message_loop_impl.cc:96
#45 0x00007ffff63e7e9d in fml::MessageLoop::Run (this=0x7fffc4000b60) at ../../flutter/fml/message_loop.cc:49
#46 0x00007ffff63fdfe7 in fml::Thread::Thread(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0::operator()() const (this=0xb7d288 <dart::observatory::observatory_assets_archive_+7042104>)
    at ../../flutter/fml/thread.cc:35
#47 0x00007ffff63fdf3d in std::__1::__invoke<fml::Thread::Thread(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0> (__f=...) at ../../third_party/libcxx/include/type_traits:3530
#48 0x00007ffff63fdee5 in std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, fml::Thread::Thread(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, fml::Thread::Thread(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0>&, std::__1::__tuple_indices<>) (__t=...) at ../../third_party/libcxx/include/thread:341
#49 0x00007ffff63fdc78 in std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, fml::Thread::Thread(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0> >(void*) (__vp=0xb7d280 <dart::observatory::observatory_assets_archive_+7042096>) at ../../third_party/libcxx/include/thread:351
#50 0x00007ffff3e33609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#51 0x00007ffff3c5d293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
```
</details>

It appears to be a use-after-free issue. I spent some time digging in, and couldn't identify any obvious differences between go-flutter-desktop and the official Linux embedder modulo the glfw/GTK differences. They both configure the engine in the same way before starting it, and neither seems to do any special preparation before shutting down the engine when glfw/GTK say it's time to close the window.

go-flutter-desktop uses a single platform/render thread like the Linux embedder. The segfault occurs after it calls FlutterEngineShutdown but before that function returns, and before FlutterEngineDeinitialize returns in FlutterEngineShutdown.

The issue seems to be caused by a SkiaGPUObject calling Unref on the io_manager SkiaUnrefQueue after the IO thread teardown code at shell.cc:454. In this case, a flutter::Picture is deleted on a DartWorker thread, _after_ a breakpoint placed at shell.cc:478 (i.e., at the end of the Shell::Shell destructor), shortly before the segmentation fault.

<details><summary>Unref called from DartWorker, late</summary>

```
Thread 37 "DartWorker" hit Breakpoint 3, flutter::SkiaUnrefQueue::Unref (this=0x7fffac0108d0, object=0x7fffb83bf860) at ../../flutter/flow/skia_gpu_object.cc:29
29          task_runner_->PostDelayedTask(
(gdb) bt
#0  flutter::SkiaUnrefQueue::Unref (this=0x7fffac0108d0, object=0x7fffb83bf860) at ../../flutter/flow/skia_gpu_object.cc:29
#1  0x00007ffff74b491e in flutter::SkiaGPUObject<flutter::DisplayList>::reset (this=0x7fffb82c6e70) at ../../flutter/flow/skia_gpu_object.h:76
#2  0x00007ffff74b4869 in flutter::SkiaGPUObject<flutter::DisplayList>::~SkiaGPUObject (this=0x7fffb82c6e70) at ../../flutter/flow/skia_gpu_object.h:68
#3  0x00007ffff796253b in flutter::Picture::~Picture (this=0x7fffb82c6e30) at ../../flutter/lib/ui/painting/picture.cc:55
#4  0x00007ffff7962579 in flutter::Picture::~Picture (this=0x7fffb82c6e30) at ../../flutter/lib/ui/painting/picture.cc:55
#5  0x00007ffff79698c6 in fml::RefCountedThreadSafe<flutter::Picture>::Release (this=0x7fffb82c6e50) at ../../flutter/fml/memory/ref_counted.h:73
#6  0x00007ffff7969159 in flutter::RefCountedDartWrappable<flutter::Picture>::ReleaseDartWrappableReference (this=0x7fffb82c6e30) at ../../flutter/lib/ui/dart_wrapper.h:22
#7  0x00007ffff75a12e2 in tonic::DartWrappable::FinalizeDartWrapper (isolate_callback_data=0x7fffb8054a20, peer=0x7fffb82c6e30) at ../../flutter/third_party/tonic/dart_wrappable.cc:77
#8  0x00007ffff7ead12c in dart::FinalizablePersistentHandle::Finalize (isolate_group=0x7fffb80029b0, handle=0x7fffb80589f0) at ../../third_party/dart/runtime/vm/dart_api_impl.cc:749
#9  0x00007ffff7aabe7d in dart::Handles<5, 64, 0>::HandlesBlock::Visit (this=0x7fffb8058800, visitor=0x7fffb06fece0) at ../../third_party/dart/runtime/vm/handles_impl.h:295
#10 dart::Handles<5, 64, 0>::Visit (this=<optimized out>, visitor=0x7fffb06fece0) at ../../third_party/dart/runtime/vm/handles_impl.h:55
#11 dart::FinalizablePersistentHandles::VisitHandles (this=<optimized out>, visitor=0x7fffb06fece0) at ../../third_party/dart/runtime/vm/dart_api_state.h:545
#12 dart::ApiState::VisitWeakHandlesUnlocked (this=<optimized out>, visitor=0x7fffb06fece0) at ../../third_party/dart/runtime/vm/dart_api_state.h:741
#13 dart::IsolateGroup::~IsolateGroup (this=this@entry=0x7fffb80029b0) at ../../third_party/dart/runtime/vm/isolate.cc:416
#14 0x00007ffff7aac9c0 in dart::IsolateGroup::Shutdown (this=0x7fffb80029b0) at ../../third_party/dart/runtime/vm/isolate.cc:527
#15 0x00007ffff7c08959 in dart::ThreadPool::WorkerLoop (this=this@entry=0xbe54d0, worker=worker@entry=0x7fff8c008410) at ../../third_party/dart/runtime/vm/thread_pool.cc:158
#16 0x00007ffff7c08df7 in dart::ThreadPool::Worker::Main (args=140735542232080) at ../../third_party/dart/runtime/vm/thread_pool.cc:323
#17 0x00007ffff7b7c841 in dart::ThreadStart (data_ptr=<optimized out>) at ../../third_party/dart/runtime/vm/os_thread_linux.cc:154
#18 0x00007ffff3e32609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#19 0x00007ffff3d57293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
```
</details>

Removing the call to `compute` in main.dart, the SkiaGPUObject<DisplayList> is torn down on the io.flutter.ui thread during flutter::Picture::dispose, before the breakpoint at shell.cc:478 is hit:

<details><summary>Unref called from UI thread</summary>

```
Thread 11 "io.flutter.ui" hit Breakpoint 3, flutter::SkiaUnrefQueue::Unref (this=0x7fffb00108d0, object=0x7fffbc319f80) at ../../flutter/flow/skia_gpu_object.cc:29
29          task_runner_->PostDelayedTask(
(gdb) bt
#0  flutter::SkiaUnrefQueue::Unref (this=0x7fffb00108d0, object=0x7fffbc319f80) at ../../flutter/flow/skia_gpu_object.cc:29
#1  0x00007ffff74b491e in flutter::SkiaGPUObject<flutter::DisplayList>::reset (this=0x7fffbc05a3a0) at ../../flutter/flow/skia_gpu_object.h:76
#2  0x00007ffff7962b1a in flutter::Picture::dispose (this=0x7fffbc05a360) at ../../flutter/lib/ui/painting/picture.cc:77
#3  0x00007ffff79694ca in tonic::DartDispatcher<tonic::IndicesHolder<>, void (flutter::Picture::*)()>::Dispatch(void (flutter::Picture::*)()) (this=0x7fffce18c750, 
    func=(void (flutter::Picture::*)(flutter::Picture * const)) 0x7ffff7962af0 <flutter::Picture::dispose()>) at ../../flutter/third_party/tonic/dart_args.h:151
#4  0x00007ffff796940f in tonic::DartCall<void (flutter::Picture::*)()> (func=(void (flutter::Picture::*)(flutter::Picture * const)) 0x7ffff7962af0 <flutter::Picture::dispose()>, args=0x7fffce18c830) at ../../flutter/third_party/tonic/dart_args.h:204
#5  0x00007ffff7962305 in flutter::Picture_dispose (args=0x7fffce18c830) at ../../flutter/lib/ui/painting/picture.cc:29
#6  0x00007ffff7aeef97 in dart::NativeEntry::AutoScopeNativeCallWrapperNoStackCheck (args=0x7fffce18c830, func=0x7ffff79622d0 <flutter::Picture_dispose(_Dart_NativeArguments*)>) at ../../third_party/dart/runtime/vm/native_entry.cc:217
#7  0x00007fffac682764 in ?? ()
#8  0x00007fffbc05acd0 in ?? ()
#9  0x0000000001000001 in ?? ()
#10 0x00007fffce18c880 in ?? ()
#11 0x00007fffce18c878 in ?? ()
#12 0x00007fff91d47361 in ?? ()
#13 0x00007fffa600bd11 in ?? ()
#14 0x00007fffac70d591 in ?? ()
#15 0x00007fffce18c8a8 in ?? ()
#16 0x00007fffcea29c13 in ?? ()
#17 0x00007fffac708041 in ?? ()
#18 0x00007fffce7f8cf9 in ?? ()
#19 0x00007fffac708041 in ?? ()
#20 0x00007fffac708041 in ?? ()
#21 0x00007fff91c989d1 in ?? ()
#22 0x00007fffa600bd41 in ?? ()
#23 0x00007fffce18c8f0 in ?? ()
#24 0x00007fff917cf04f in ?? ()
#25 0x00007fffce7f8cf9 in ?? ()
#26 0x00007fffce7f8cf9 in ?? ()
#27 0x00007fffac708041 in ?? ()
#28 0x00007fffac708041 in ?? ()
#29 0x00007fffac708041 in ?? ()
#30 0x00007fffa600b9f1 in ?? ()
#31 0x00007fff91c98aa1 in ?? ()
#32 0x00007fffce18c938 in ?? ()
#33 0x00007fffcea29b44 in ?? ()
#34 0x00007fffac708041 in ?? ()
#35 0x00007fffce7f76a9 in ?? ()
#36 0x00007fffac708041 in ?? ()
#37 0x00007fffac708041 in ?? ()
#38 0x00007fffac708041 in ?? ()
#39 0x00007fffa50fb1e1 in ?? ()
#40 0x00007fffa600ba41 in ?? ()
#41 0x00007fffce18c970 in ?? ()
#42 0x00007fffcea1ed50 in ?? ()
#43 0x00007fffce7f76a9 in ?? ()
#44 0x00007fffac708041 in ?? ()
#45 0x00007fffac708041 in ?? ()
#46 0x00007fff92c29d41 in ?? ()
#47 0x00007fffa50fb2e1 in ?? ()
#48 0x00007fffce18c9b8 in ?? ()
#49 0x00007fffa6fcaeba in ?? ()
#50 0x00007fffce7f76a9 in ?? ()
#51 0x00007fffce7f76a9 in ?? ()
#52 0x00007fffac708041 in ?? ()
#53 0x00007fffac708041 in ?? ()
#54 0x00007fffac708041 in ?? ()
#55 0x00007fff91d22cc1 in ?? ()
#56 0x00007fff92c29f01 in ?? ()
#57 0x00007fffce18ca10 in ?? ()
#58 0x00007fff917b1e31 in ?? ()
#59 0x00007fffac708041 in ?? ()
#60 0x00007fffce7f7729 in ?? ()
#61 0x00007fffac708041 in ?? ()
#62 0x00007fff91ac3c41 in ?? ()
#63 0x00007fffce7f76a9 in ?? ()
#64 0x00007fffac708041 in ?? ()
#65 0x00007fffac708041 in ?? ()
#66 0x00007fff91d20fe1 in ?? ()
#67 0x00007fff91d22e61 in ?? ()
#68 0x00007fffce18ca80 in ?? ()
#69 0x00007fff917b1209 in ?? ()
#70 0x00007fff91ac2f81 in ?? ()
#71 0x00007fffac708041 in ?? ()
#72 0x00007fffac708041 in ?? ()
#73 0x00007fffac708041 in ?? ()
#74 0x00007fffac708061 in ?? ()
#75 0x00007fffa6e27659 in ?? ()
#76 0x00007fff91d1f5a1 in ?? ()
#77 0x00007fffac708041 in ?? ()
#78 0x00007fffac708041 in ?? ()
#79 0x00007fffac708041 in ?? ()
#80 0x00007fff91d1f811 in ?? ()
#81 0x00007fff91d213c1 in ?? ()
#82 0x00007fffce18cad8 in ?? ()
#83 0x00007fff917b09ef in ?? ()
#84 0x00007fffac708071 in ?? ()
#85 0x00007fff929e8ea1 in ?? ()
#86 0x0000000000000000 in ?? ()
```
</details>

After that, the GrGLContext destructor runs, then the breakpoint at shell.cc:478, then the app exits normally. The following breakpoints were used:

```
break shell.cc:479
break skia_gpu_object.cc:29
break FlutterEngineShutdown
break GrGLContext::~GrGLContext
```

Let me know if you need any additional information from me on how the go-flutter-desktop embedder operates, or if there are any caveats about threading/isolates/goroutines we need to keep in mind.

---

I tried running on the GLFW example in flutter/examples to see if it showed a similar issue (in the hopes of comparing apples to apples), but it failed to start:

```
[ERROR:flutter/shell/platform/embedder/embedder_surface_gl.cc(102)] Could not create a resource context for async texture uploads. Expect degraded performance. Set a valid make_resource_current callback on FlutterOpenGLRendererConfig.
../../third_party/skia/src/gpu/gl/GrGLInterfaceAutogen.cpp:263 GrGLInterface::validate() failed.
[ERROR:flutter/shell/gpu/gpu_surface_gl.cc(53)] Failed to set up Skia Gr context.
[ERROR:flutter/shell/common/platform_view.cc(83)] Failed to create platform view rendering surface
```