Skip to content
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

Crash fix: macOS (Silicon) fix crash on joypad removal #55034

Merged
merged 1 commit into from
Nov 17, 2021
Merged

Crash fix: macOS (Silicon) fix crash on joypad removal #55034

merged 1 commit into from
Nov 17, 2021

Conversation

plink-plonk-will
Copy link
Contributor

ff_device is initialised in config_force_feedback. So in line 250, if FFIsForceFeedback(ioservice) != FF_OK then config_force_feedback isn't called, and ff_device is left uninitialised. This then causes a crash on line 60 when the controller is removed and ff_device is incorrectly freed.

This was noticed when a Dualshock 4 or Dualsense (bluetooth) was left to disconnect, or force disconnected while the build is running with the following stack trace:

This fix ensures the ff_device variable is default intialised to 0, and when released set back to 0.

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib         0x000000018a4c8e68 __pthread_kill + 8
1   libsystem_pthread.dylib       0x000000018a4fb43c pthread_kill + 292
2   libsystem_c.dylib             0x000000018a443460 abort + 104
3   godot.osx.tools.arm64         0x0000000104742a14 handle_crash(int) + 2480
4   libsystem_platform.dylib       0x000000018a546c44 _sigtramp + 56
5   godot.osx.tools.arm64         0x000000010477d0d4 joypad::free() + 104
6   godot.osx.tools.arm64         0x000000010477d0d4 joypad::free() + 104
7   godot.osx.tools.arm64         0x000000010477e5dc JoypadOSX::_device_removed(int, __IOHIDDevice*) + 300
8   godot.osx.tools.arm64         0x000000010477f4a8 joypad_removed_callback(void*, int, void*, __IOHIDDevice*) + 52
9   com.apple.framework.IOKit     0x000000018ccc72e0 __IOHIDManagerDeviceRemoved + 416
10  com.apple.framework.IOKit     0x000000018cc85548 IODispatchCalloutFromCFMessage + 328
11  com.apple.CoreFoundation       0x000000018a62a2a8 __CFMachPortPerform + 308
12  com.apple.CoreFoundation       0x000000018a5fb368 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 60
13  com.apple.CoreFoundation       0x000000018a5fb224 __CFRunLoopDoSource1 + 596
14  com.apple.CoreFoundation       0x000000018a5f96a4 __CFRunLoopRun + 2372
15  com.apple.CoreFoundation       0x000000018a5f85e8 CFRunLoopRunSpecific + 600
16  godot.osx.tools.arm64         0x000000010477ea84 JoypadOSX::poll_joypads() const + 36
17  godot.osx.tools.arm64         0x000000010477eabc JoypadOSX::process_joypads() + 32
18  godot.osx.tools.arm64         0x0000000104747680 OS_OSX::run() + 300
19  godot.osx.tools.arm64         0x000000010477bdd0 main + 940
20  libdyld.dylib                 0x000000018a519450 start + 4

@plink-plonk-will plink-plonk-will requested a review from a team as a code owner November 16, 2021 20:39
@akien-mga akien-mga added this to the 4.0 milestone Nov 16, 2021
@akien-mga
Copy link
Member

Looks good, but the two commits are directly related and should be squashed together to be a self-contained fix. See PR workflow.

@plink-plonk-will
Copy link
Contributor Author

Thank you for the link explaining that @akien-mga ! I've squashed the commits together now.

Copy link
Member

@bruvzg bruvzg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change is fine, but need a style fix:

 diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index 0b511e3..e4c4ec0 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -349,7 +349,7 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
 	{                                   \
 		if (ret != FF_OK) {             \
 			FFReleaseDevice(ff_device); \
-			ff_device = 0; \
+			ff_device = 0;              \
 			return false;               \
 		}                               \
 	}

Also, since it's reference, it probably should be nullptr not 0.

@plink-plonk-will
Copy link
Contributor Author

Fixed style, and also changed to nullptr.

@@ -55,9 +55,10 @@ void joypad::free() {
if (device_ref) {
IOHIDDeviceUnscheduleFromRunLoop(device_ref, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE);
}
if (ff_device) {
if (ff_device != nullptr) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pointers evaluate well as booleans so we usually use the shorter if (pointer) style instead of making the != nullptr part explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following the style on line 247. I can change both though?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's not very important, but for consistency's sake I guess you can change the other two occurrences on lines 247 and 607.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@@ -68,7 +68,7 @@ struct joypad {

io_service_t ffservice = 0; /* Interface for force feedback, 0 = no ff */
FFCONSTANTFORCE ff_constant_force;
FFDeviceObjectReference ff_device;
FFDeviceObjectReference ff_device = nullptr;
FFEffectObjectReference ff_object;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this could be initialized to nullptr too just to be safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@akien-mga
Copy link
Member

FYI, the email used to author your commit doesn't seem to be linked to your GitHub account (see the email in https://patch-diff.githubusercontent.com/raw/godotengine/godot/pull/55034.patch ), which is why the commit is shown as authored and committed by two different identities:
image

It's not a problem per se, but if you want to claim the commit as a contribution for your @plucky-git account, you can add this email as secondary email in your GitHub settings, or edit the commit to change its Git author details.

@akien-mga akien-mga merged commit f7b482d into godotengine:master Nov 17, 2021
@akien-mga
Copy link
Member

Thanks! And congrats for your first merged Godot contribution 🎉

@akien-mga
Copy link
Member

Cherry-picked for 3.5.

@akien-mga akien-mga removed the cherrypick:3.x Considered for cherry-picking into a future 3.x release label Nov 17, 2021
@plink-plonk-will plink-plonk-will deleted the macos-fix-crash-on-joypad-removal branch November 17, 2021 17:52
@akien-mga
Copy link
Member

Cherry-picked for 3.4.1.

@akien-mga
Copy link
Member

Cherry-picked for 3.3.5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants