Automatic sizing of stack variables
Version and Platform (required):
- Binary Ninja Version: 4.0.4958, ddff9339
- OS: macos
- OS Version: 14.4
- CPU Architecture: arm64
Internal binary major dine favor.
Notice how IDA Pro automatically determines the size of payload here
uint64_t __fastcall DjiProductInfo_GetPayloadInfoHandle(struct CommandManager *mgr, struct CommandHeader *header)
{
__int64 payload[14]; // [xsp+38h] [xbp+38h] BYREF
__int64 v6; // [xsp+A8h] [xbp+A8h]
__int64 v7[4]; // [xsp+B0h] [xbp+B0h] BYREF
uint64_t v8; // [xsp+D0h] [xbp+D0h]
T_DjiOsalHandler *osal; // [xsp+D8h] [xbp+D8h]
osal = DjiPlatform_GetOsalHandler();
memset(payload, 0, sizeof(payload));
v6 = 0LL;
memset(v7, 0, sizeof(v7));
v8 = osal->MutexLock((T_DjiMutexHandle)s_productInfoMutex);
if ( v8 )
{
DjiLogger_Output("core", 0, "[%s:%d) lock mutex error: 0x%08llX.", "DjiProductInfo_GetPayloadInfoHandle", 203LL, v8);
return v8;
}
else
{
strncpy((char *)payload + 1, s_productInfo, 0x1FuLL);
*(__int64 *)((char *)&payload[4] + 1) = *(_QWORD *)&s_productInfo[32];
*(__int64 *)((char *)&payload[5] + 1) = *(_QWORD *)&s_productInfo[40];
strncpy((char *)&payload[6] + 1, byte_292970, 0x3FuLL);
BYTE1(v6) = dword_2929B8;
WORD1(v6) = dword_2929BC;
HIDWORD(v6) = *(int *)((char *)&dword_2929BC + 2);
strncpy((char *)v7, byte_2929C2, 0x1FuLL);
v8 = osal->MutexUnlock((T_DjiMutexHandle)s_productInfoMutex);
if ( v8 )
{
DjiLogger_Output(
"core",
0,
"[%s:%d) unlock mutex error: 0x%08llX.",
"DjiProductInfo_GetPayloadInfoHandle",
221LL,
v8);
return v8;
}
else
{
v8 = DjiCommand_SendAckData(mgr, header, payload, 0x98);
if ( v8 )
DjiLogger_Output(
"core",
0,
"[%s:%d) get DJI product information ack error:0x%08llX",
"DjiProductInfo_GetPayloadInfoHandle",
228LL,
v8);
return v8;
}
}
}
Why doesn't BN do the same?
0009ecc4 uint64_t DjiProductInfo_GetPayloadInfoHandle(struct CommandManager* mgr, struct CommandHeader* header)
0009ecd4 int64_t x2
0009ecd4 int64_t var_c8 = x2
0009ecd8 struct T_DjiOsalHandler* osal = DjiPlatform_GetOsalHandler()
0009ece4 int64_t payload = 0
0009ece4 int64_t s
0009ece4 __builtin_memset(s: &s, c: 0, n: 0x90)
0009ed2c payload.b = 0
0009ed44 uint64_t x0_2 = osal->MutexLock(mutex: s_productInfoMutex)
0009ed54 uint64_t x0_4
0009ed54 if (x0_2 != 0)
0009ed84 DjiLogger_Output(tag: "core", level: 0, fmt: "[%s:%d) lock mutex error: 0x%08l…", "DjiProductInfo_GetPayloadInfoHan…", 0xcb, x0_2)
0009ed88 x0_4 = x0_2
0009ed54 else
0009eda4 strncpy(&payload:1, &PRODUCT_INFO, 0x1f)
0009edb0 void* x0_6 = PRODUCT_INFO.appId[0].q
0009edb8 int64_t var_88 = x0_6
0009edb8 int64_t var_80 = *(x0_6 + 0x28)
0009edd0 int64_t var_78
0009edd0 strncpy(&var_78:1, &PRODUCT_INFO.developerAccount, 0x3f)
0009ede4 int64_t var_38
0009ede4 var_38:1.b = (data_2929b8).b
0009ee00 var_38:2.d = data_2929bc.d
0009ee08 var_38:4.d = data_2929be.d
0009ee20 int64_t var_30
0009ee20 strncpy(&var_30, &data_2929c2, 0x1f)
0009ee38 uint64_t x0_13 = osal->MutexUnlock(mutex: s_productInfoMutex)
0009ee48 if (x0_13 != 0)
0009ee78 DjiLogger_Output(tag: "core", level: 0, fmt: "[%s:%d) unlock mutex error: 0x%0…", "DjiProductInfo_GetPayloadInfoHan…", 0xdd, x0_13)
0009ee7c x0_4 = x0_13
0009ee48 else
0009ee98 uint64_t x0_16 = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x98)
0009eea8 if (x0_16 != 0)
0009eed8 DjiLogger_Output(tag: "core", level: 0, fmt: "[%s:%d) get DJI product informat…", "DjiProductInfo_GetPayloadInfoHan…", 0xe4, x0_16)
0009eedc x0_4 = x0_16
0009eee4 return x0_4
I know the size is 0x98 because I know what payload_size is here
0009ee98 uint64_t x0_16 = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x98)
but BN does auto-generate these and should know the size is at least 0x90
0009ece4 __builtin_memset(s: &s, c: 0, n: 0x90)
Regardless, IDA Pro generates the correct sizes and memsets, including for var30
memset(payload, 0, sizeof(payload));
v6 = 0LL;
memset(v7, 0, sizeof(v7));
whereas BN misses var30 completely.
Changing payload size to 0x98 in IDA Pro does this
uint64_t __fastcall DjiProductInfo_GetPayloadInfoHandle(struct CommandManager *mgr, struct CommandHeader *header)
{
char payload[152]; // [xsp+38h] [xbp+38h] BYREF
uint64_t v6; // [xsp+D0h] [xbp+D0h]
T_DjiOsalHandler *osal; // [xsp+D8h] [xbp+D8h]
osal = DjiPlatform_GetOsalHandler();
memset(payload, 0, sizeof(payload));
v6 = osal->MutexLock((T_DjiMutexHandle)s_productInfoMutex);
if ( v6 )
{
DjiLogger_Output("core", 0, "[%s:%d) lock mutex error: 0x%08llX.", "DjiProductInfo_GetPayloadInfoHandle", 203LL, v6);
return v6;
}
else
{
strncpy(&payload[1], s_productInfo, 0x1FuLL);
*(_QWORD *)&payload[33] = *(_QWORD *)&s_productInfo[32];
*(_QWORD *)&payload[41] = *(_QWORD *)&s_productInfo[40];
strncpy(&payload[49], byte_292970, 0x3FuLL);
payload[113] = dword_2929B8;
*(_WORD *)&payload[114] = dword_2929BC;
*(_DWORD *)&payload[116] = *(int *)((char *)&dword_2929BC + 2);
strncpy(&payload[120], byte_2929C2, 0x1FuLL);
v6 = osal->MutexUnlock((T_DjiMutexHandle)s_productInfoMutex);
if ( v6 )
{
DjiLogger_Output(
"core",
0,
"[%s:%d) unlock mutex error: 0x%08llX.",
"DjiProductInfo_GetPayloadInfoHandle",
221LL,
v6);
return v6;
}
else
{
v6 = DjiCommand_SendAckData(mgr, header, payload, 0x98);
if ( v6 )
DjiLogger_Output(
"core",
0,
"[%s:%d) get DJI product information ack error:0x%08llX",
"DjiProductInfo_GetPayloadInfoHandle",
228LL,
v6);
return v6;
}
}
}
which looks right. The stack layout according to IDA Pro is
char payload[152]; // [xsp+38h] [xbp+38h] BYREF
uint64_t v6; // [xsp+D0h] [xbp+D0h]
T_DjiOsalHandler *osal; // [xsp+D8h] [xbp+D8h]
but BN generates phantom unused variables x2 (passed in register X2) and var_c8 (at stack offset -0xc8).
0009ecc4 uint64_t DjiProductInfo_GetPayloadInfoHandle(struct CommandManager* mgr, struct CommandHeader* header)
0009ecd4 int64_t x2
0009ecd4 int64_t var_c8 = x2
0009ecd8 struct T_DjiOsalHandler* osal = DjiPlatform_GetOsalHandler()
0009ece4 char payload[0x98]
0009ece4 payload[0].q = 0
0009ece4 payload[8].q = 0
0009ecec payload[0x10].q = 0
0009ecec payload[0x18].q = 0
0009ecf4 payload[0x20].q = 0
0009ecf4 payload[0x28].q = 0
0009ecfc payload[0x30].q = 0
0009ecfc payload[0x38].q = 0
0009ed04 payload[0x40].q = 0
0009ed04 payload[0x48].q = 0
0009ed0c payload[0x50].q = 0
0009ed0c payload[0x58].q = 0
0009ed14 payload[0x60].q = 0
0009ed14 payload[0x68].q = 0
0009ed1c payload[0x70].q = 0
0009ed1c payload[0x78].q = 0
0009ed24 payload[0x80].q = 0
0009ed24 payload[0x88].q = 0
0009ed28 payload[0x90].q = 0
0009ed2c payload[0] = 0
0009ed44 uint64_t x0_2 = osal->MutexLock(mutex: s_productInfoMutex)
0009ed54 uint64_t x0_4
0009ed54 if (x0_2 != 0)
0009ed84 DjiLogger_Output(tag: "core", level: 0, fmt: "[%s:%d) lock mutex error: 0x%08l…", "DjiProductInfo_GetPayloadInfoHan…", 0xcb, x0_2)
0009ed88 x0_4 = x0_2
0009ed54 else
0009eda4 strncpy(&payload[1], &PRODUCT_INFO, 0x1f)
0009edb0 void* x0_6 = PRODUCT_INFO.appId[0].q
0009edb8 payload[0x21].q = x0_6
0009edb8 payload[0x29].q = *(x0_6 + 0x28)
0009edd0 strncpy(&payload[0x31], &PRODUCT_INFO.developerAccount, 0x3f)
0009ede4 payload[0x71] = (data_2929b8).b
0009ee00 payload[0x72].d = data_2929bc.d
0009ee08 payload[0x74].d = data_2929be.d
0009ee20 strncpy(&payload[0x78], &data_2929c2, 0x1f)
0009ee38 uint64_t x0_13 = osal->MutexUnlock(mutex: s_productInfoMutex)
0009ee48 if (x0_13 != 0)
0009ee78 DjiLogger_Output(tag: "core", level: 0, fmt: "[%s:%d) unlock mutex error: 0x%0…", "DjiProductInfo_GetPayloadInfoHan…", 0xdd, x0_13)
0009ee7c x0_4 = x0_13
0009ee48 else
0009ee98 uint64_t x0_16 = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x98)
0009eea8 if (x0_16 != 0)
0009eed8 DjiLogger_Output(tag: "core", level: 0, fmt: "[%s:%d) get DJI product informat…", "DjiProductInfo_GetPayloadInfoHan…", 0xe4, x0_16)
0009eedc x0_4 = x0_16
0009eee4 return x0_4
Related to #5395.
Duplicate of #2570
Do I correctly understand that this bug has been open for... ugh... close to 3 years now?