SDL: Fixed unaligned access in NVIDIA SHIELD Controller driver (d4da5)

From d4da5df0887b87ba902cbaa870c99929deb79791 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 27 Jan 2026 11:25:38 -0800
Subject: [PATCH] Fixed unaligned access in NVIDIA SHIELD Controller driver

Also refactored the LOAD16() and LOAD32() macros into SDL_hidapijoystick_c.h

(cherry picked from commit cae2a28f5b470fc56de14c71a7edcddae101312d)
---
 src/joystick/hidapi/SDL_hidapi_flydigi.c    |  2 --
 src/joystick/hidapi/SDL_hidapi_ps3.c        |  2 --
 src/joystick/hidapi/SDL_hidapi_ps4.c        |  6 ----
 src/joystick/hidapi/SDL_hidapi_ps5.c        |  6 ----
 src/joystick/hidapi/SDL_hidapi_shield.c     | 38 ++++++++++++++-------
 src/joystick/hidapi/SDL_hidapi_steam_hori.c |  2 --
 src/joystick/hidapi/SDL_hidapi_xboxone.c    |  2 --
 src/joystick/hidapi/SDL_hidapijoystick_c.h  |  6 ++++
 8 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/src/joystick/hidapi/SDL_hidapi_flydigi.c b/src/joystick/hidapi/SDL_hidapi_flydigi.c
index 3979861733ba3..96b8b967cbce2 100644
--- a/src/joystick/hidapi/SDL_hidapi_flydigi.c
+++ b/src/joystick/hidapi/SDL_hidapi_flydigi.c
@@ -80,8 +80,6 @@ enum
 #define FLYDIGI_V2_ACQUIRE_CONTROLLER_COMMAND 0x1C
 #define FLYDIGI_V2_INPUT_REPORT         0xEF
 
-#define LOAD16(A, B)       (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
-
 typedef struct
 {
     SDL_HIDAPI_Device *device;
diff --git a/src/joystick/hidapi/SDL_hidapi_ps3.c b/src/joystick/hidapi/SDL_hidapi_ps3.c
index 95f6d99880414..ede49cbaa753a 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps3.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps3.c
@@ -32,8 +32,6 @@
 // Define this if you want to log all packets from the controller
 // #define DEBUG_PS3_PROTOCOL
 
-#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
-
 typedef enum
 {
     k_EPS3ReportIdState = 1,
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index de2c047ad7633..3f57a6d30f593 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -44,12 +44,6 @@
 
 #define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
 
-#define LOAD16(A, B)       (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
-#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) |  \
-                            (((Uint32)(B)) << 8) |  \
-                            (((Uint32)(C)) << 16) | \
-                            (((Uint32)(D)) << 24))
-
 enum
 {
     SDL_GAMEPAD_BUTTON_PS4_TOUCHPAD = 11
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 526d6a37069ba..133db1a13750a 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -43,12 +43,6 @@
 #define ACCEL_RES_PER_G                 8192.0f
 #define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
 
-#define LOAD16(A, B)       (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
-#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) |  \
-                            (((Uint32)(B)) << 8) |  \
-                            (((Uint32)(C)) << 16) | \
-                            (((Uint32)(D)) << 24))
-
 enum
 {
     SDL_GAMEPAD_BUTTON_PS5_TOUCHPAD = 11,
diff --git a/src/joystick/hidapi/SDL_hidapi_shield.c b/src/joystick/hidapi/SDL_hidapi_shield.c
index e6a25d5c716a3..a057a04865aaf 100644
--- a/src/joystick/hidapi/SDL_hidapi_shield.c
+++ b/src/joystick/hidapi/SDL_hidapi_shield.c
@@ -289,6 +289,7 @@ static bool HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *dev
 static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
 {
     Uint64 timestamp = SDL_GetTicksNS();
+    Sint16 axis;
 
     if (ctx->last_state[3] != data[3]) {
         Uint8 hat;
@@ -346,14 +347,20 @@ static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SD
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[2] & 0x80) != 0));
     }
 
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[4]) - 0x8000);
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[6]) - 0x8000);
+    axis = LOAD16(data[4], data[5]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
+    axis = LOAD16(data[6], data[7]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
 
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[8]) - 0x8000);
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[10]) - 0x8000);
+    axis = LOAD16(data[8], data[9]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
+    axis = LOAD16(data[10], data[11]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
 
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[12]) - 0x8000);
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[14]) - 0x8000);
+    axis = LOAD16(data[12], data[13]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
+    axis = LOAD16(data[14], data[15]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
 
     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
 }
@@ -379,6 +386,7 @@ static void HIDAPI_DriverShield_HandleTouchPacketV103(SDL_Joystick *joystick, SD
 static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
 {
     Uint64 timestamp = SDL_GetTicksNS();
+    Sint16 axis;
 
     if (size < 23) {
         return;
@@ -434,14 +442,20 @@ static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SD
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[4] & 0x01) != 0));
     }
 
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[9]) - 0x8000);
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[11]) - 0x8000);
+    axis = LOAD16(data[9], data[10]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
+    axis = LOAD16(data[11], data[12]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
 
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[13]) - 0x8000);
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[15]) - 0x8000);
+    axis = LOAD16(data[13], data[14]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
+    axis = LOAD16(data[15], data[16]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
 
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[19]) - 0x8000);
-    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[21]) - 0x8000);
+    axis = LOAD16(data[19], data[20]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
+    axis = LOAD16(data[21], data[22]) - 0x8000;
+    SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
 
     if (ctx->last_state[17] != data[17]) {
         //SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_SHARE, ((data[17] & 0x01) != 0));
diff --git a/src/joystick/hidapi/SDL_hidapi_steam_hori.c b/src/joystick/hidapi/SDL_hidapi_steam_hori.c
index d92634d54accd..8d445c979119f 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam_hori.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam_hori.c
@@ -32,8 +32,6 @@
 /* Define this if you want to log all packets from the controller */
 /*#define DEBUG_HORI_PROTOCOL*/
 
-#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
-
 enum
 {
     SDL_GAMEPAD_BUTTON_HORI_QAM = 11,
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index 6f7e57e2c3f2f..11e7f574cece3 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -52,8 +52,6 @@
 #define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
 #define XINPUT_GAMEPAD_TRIGGER_THRESHOLD    -25058 // Uint8 30 scaled to Sint16 full range
 
-#define LOAD16(A, B)       (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
-
 enum
 {
     SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON = 11
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index 857b466980335..6129441881a47 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -176,6 +176,12 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverFlydigi;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSInput;
 extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverZUIKI;
 
+#define LOAD16(A, B)       (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
+#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) |  \
+                            (((Uint32)(B)) << 8) |  \
+                            (((Uint32)(C)) << 16) | \
+                            (((Uint32)(D)) << 24))
+
 // Return true if a HID device is present and supported as a joystick of the given type
 extern bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type);