map.find() 如何查看输出的程序集

How map.find() works looking at the outputted assembly

我正在调试 Android 应用程序的崩溃并遇到以下几行:

void myobject::save(std::string toSave) {
...
}
...
std::map<std::string, std::string> dict;
...    
myobject::save(dict.find("username")->second);

生成的程序集:

02F05DFC               bl         _ZNKSt6__ndk16__treeINS_12__value_typeINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEES7_EENS_19__map_value_compareIS7_S8_NS_4lessIS7_EELb1EEENS5_IS8_EEE4findIS7_EENS_21__tree_const_iteratorIS8_PNS_11__tree_nodeIS8_PvEEiEERKT_
3096                   str        r6, [sp, #0x108 + var_48]
0146                   mov        r1, r0
CDE92E66               strd       r6, r6, [sp, #0x108 + var_50]
11F81C2F               ldrb       r2, [r1, #0x1c]!
12F0010F               tst.w      r2, #0x1
06D1                   bne        loc_THERE

                  loc_FIRST:
D1E90002               ldrd       r0, r2, [r1]
8968                   ldr        r1, [r1, #0x8]
3091                   str        r1, [sp, #0x108 + var_48]
CDE92E02               strd       r0, r2, [sp, #0x108 + var_50]
04E0                   b          loc_HERE

                  loc_THERE:
D0E90821               ldrd       r2, r1, [r0, #0x20]
2EA8                   add        r0, sp, #0xb8_ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcj
FDF743FD               bl         _ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcj

                  loc_HERE:
2EA9                   add        r1, sp, #0xb8
2046                   mov        r0, r4
04F047FB               bl         _ZN6myobject11saveENSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE

我发现了错误。当 find() return 一个 end() 迭代器时发生崩溃。但是,有趣的是,崩溃发生在 new() 内部(在 basic_string::__init() 内部完成)。当 find() return 一个 end() 迭代器时,似乎 end() (end()->second) 的取消引用不会崩溃,但在将 end()->second 转换为 a 时会崩溃std::string() 就在将其传递给 myobject::save() 之前。

我试图查看 libcxx 实现,但没有找到我要找的东西。有谁知道 loc_FIRST 和 loc_THERE 这两个块的用途是什么?为什么要检查 *(r1+0x1c) == 0x1?谁能解释一下汇编代码中“->second”出现的位置?

I think it's doing a small string optimization (SSO). The loc_FIRST case would be the case where the string is contained in the SSO buffer, and just copies the 12 bytes of the string directly into the stack location for the string. The loc_THERE case is when SSO is inactive and calls std::string::__init to do the allocation and other non-SSO init work. So essentially that branch is part of the std::string construction which has been inlined into this code (but the slow non-SSO path is still out of line). The bit being checked presumably indicates whether SSO is active for that string. – BeeOnRope Mar 27 at 21:02