当前位置: 首页 > news >正文

视频网站怎么做移动广告联盟

视频网站怎么做,移动广告联盟,济宁哪里做网站,仿淘宝网站建设函数直接返回bool值和返回bool变量差异 背景 在工作中遇到一个比较诡异的问题,场景是给业务方提供的SDK有一个获取状态的函数GetStatus,函数的返回值类型是bool,在测试过程中发现,SDK返回的是false,但是业务方拿到的…

函数直接返回bool值和返回bool变量差异

背景

在工作中遇到一个比较诡异的问题,场景是给业务方提供的SDK有一个获取状态的函数GetStatus,函数的返回值类型是bool,在测试过程中发现,SDK返回的是false,但是业务方拿到的返回值是true。SDK是C语言和C++语言编写的,C语言编写接口层, C++语言编写实际逻辑,业务方是unity,使用C#语言,通过DllImport引用SDK DLL

  • DllImport声明如下
[DllImport("SDK.dll", EntryPoint="GetStatus", CharSet=CharSet.Ansi, 
CallingConventin=CallingConvention.Cdec1)]
public static extern bool GetStatus([MarshalAs(UnmanagedType.LPStr)] string key);
  • C语言接口层
// 声明
__declspec(dllexport) bool GetStatus(const char* key); 
// 定义
bool GetStatus(const char *key)
{return cpp_instance->GetStatus(key);
}
  • C++实现
    C++ 将key对应的状态保存到一个map中,key类型为std::string,值为std::any
template<class typename T>
T GetStatus(const std::string &key)
{if(!status_map_.count(key)) {return {};}const auto &value = status_map_.at(key);if(!value.has_value()) {return {};}try {return std::any_cast<T>(value);} catch (const std::exception &e) {return {};}
}

排查

C++侧排查

通过 SDK的 unity demo 调试未能复现问题,将SDK Attach到业务进程调试问题复现,由于代码中没有中间变量保留结果,都是直接将结果返回。调试不方便。在代码中增加了一行日志打印。结果问题不复现了。

  • 增加一行日志后的代码
bool GetStatus(const char *key)
{auto ret = cpp_instance->GetStatus(key);std::cout << "get status result " << ret << std::endl;return ret;
}

百思不得其解,决定反汇编调试看下,看下增加日志前和增加日志后的汇编代码。
为了方便调试和说明,这里编写了复现的简单demo,如下:

#include <iostream>typedef int (*GetBoolFuncPtr)();static bool GetBool1()
{return {};
}
static bool GetBool2()
{/*  bool ret = GetBool1();std::cout << "ret:" << ret << std::endl;return ret;*/return GetBool1();
}int main()
{/*GetBoolFuncPtr booll = reinterpret_cast<int (*)()>(GetBool1);GetBoolFuncPtr bool2 = reinterpret_cast<int (*)()>(GetBool2);std::cout << booll() << " " << bool2() << std::endl;*/std::cout << GetBool2() << std::endl;int input;std::cin >> input;return 0;
}
未增加日志打印的反汇编代码如下

未增加日志的反汇编代码
可以看到GetBool2()函数中直接返回了GetBool1()函数的结果,return {}的反汇编代码为xor al,alal表示RAX寄存的低8位, 而函数的返回值就是保存在RAX寄存中,所以对于返回值是boolC++函数,直接return {}是将RAX寄存器的低8位清零,RAX的其他位数是残值。之所以只清零低8位是因为在C++中bool 占1个字节。

增加日志的输出代码
static bool GetBool2()
{bool ret = GetBool1();std::cout << "ret:" << ret << std::endl;return ret;
}

反汇编代码
增加日志的反汇编代码
可以看到GetBool2()函数中通过一个中间变量ret保存了GetBool1()的返回值,并且打印ret的值,然后将ret返回,通过反汇编代码可以看到move byte ptr [ret], alGetBool1()的保存在al的值保存在了ret指向的地址,return ret对应的反汇编代码movezx eax, byte ptr [ret]ret的值保存到 eax寄存器,eax寄存器是RAX寄存器的低32位。这里的重点是movezx指令,movezx指令可以将较小的值用0扩展到较大的值。所以这里eax的高24位被清零。

C++侧排查总结
  • return {}返回bool值将清零RAX寄存器的低8位
  • return ret 返回bool值将清零RAX寄存器的低32位
    可以看到 增加了一行日志和没有这行日志的差别在于会清零返回值寄存器RAX的多少位。这个差别为什么会导致unity 拿到的结果不一样呢?需要继续排查。
unity排查
现状
  • 业务unity应用出现问题

  • SDK unity demo正常
    通过和业务开发沟通发现,业务unity应用后端使用的是il2cpp模式,而SDK unity demo则使用的是mono模式,也许是这里出现了问题,果然将unity demo的后端改成il2cpp模式后复现问题。

    那为什么在il2cpp模式下有问题呢?

    il2cpp模式会将C#代码转换成cpp代码,业务同学说在C#的DllImport地方增加解决了

    [return: MarshalAs(UnmanagedType.I1)]
    

    为什么增加这行代码就可以了,原来在C#中的UnmanagedType类型中bool变量是占4个字节,而使用il2cpp模式后C#的代码会被转换成C++代码。Dllimport的代码会转换成类似下面的逻辑(这里只摘出了重要代码)

    typedef  int32_t (CDECL * PInvokeFunc)(char*);
    static PInvokeFunc  il2cppPInvokeFunc;
    if(il2cppPInvokeFunc == NULL) {il2cppPInvokeFunc  = il2cpp_codegen_resolve_pinvoke<PInvokeFunc>(IL2CPP_NATIVE_STRING("SDK.dll"), "GetStatus", ....);
    }
    
结论

从转换后的代码可以看到,il2cpp C++代码解析的GetStatus函数的返回值是int32_t,也就是说SDK内部返回bool的函数,这里被解析成int32_t了,返回int32_t会从返回值寄存器RAX中读取低32位,结合前面的C++demo分析可以解释了为什么没有打印日志拿到的返回值大概率是true,因为没有打印日志,返回 false只清零了RAX寄存器的低8位,而il2cpp中读取了32位,RAX寄存器大概率有其他函数调用的残值,导致il2cpp中读取到的值大概率为true。而打印了日志,返回false清零RAX寄存器的低32位, il2cpp代码读取正确

参考

https://stackoverflow.com/questions/20035826/why-dllimport-for-c-bool-as-unmanagedtype-i1-throws-but-as-byte-it-works
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedtype?view=net-9.0

http://www.dtcms.com/a/548871.html

相关文章:

  • 高速DIC技术用于无人机旋翼动态变形与轨迹姿态分析
  • Node.js环境变量配置
  • Docker 部署 Node.js + Playwright 项目,实现浏览器截图、打印和下载
  • 所有权与解构:一次把“拆”与“留”写进类型系统的旅程 ——从语法糖到零拷贝 AST
  • 基于ASM1042通信接口芯片的两轮车充电机性能优化研究
  • hadoop之MapReduce的map工作流程
  • 民治做网站公司门户网站开发要求
  • 设计师网站欣赏企业官网模板图下载
  • 图像与视频页面的数据提取:从OCR到关键帧抽取的一场“视觉接管”
  • 常州城乡建设学校网站上海自动seo
  • Android15 Camera系统调试操作
  • 建模工具Enterprise Architect:敏捷开发中的架构治理与迭代适配
  • [HDiffPatch] 补丁算法 | `patch_decompress_with_cache` | `getStreamClip` | RLE游程编码
  • 【C++ vector 深度解析】:动态数组的使用与底层原理实战
  • 【0基础学算法】前缀和刷题日志(三):连续数组、矩阵区域和
  • 学习网站建设与管理汉沽集团网站建设
  • 10月30日
  • ESP32开发指南(基于IDF):连接AWS,乐鑫官方esp-aws-iot-master例程实验、跑通
  • Cocos资源加密方案解析
  • 从零开始的云原生之旅(六):DaemonSet 实战日志采集器
  • 网站建设人员任职要求电器类网站设计
  • [论文阅读] AI + Debug | 基于大语言模型的GitHub故障复现测试用例生成方法解析
  • 关于App的gradle降级问题的总结
  • 从零开始的云原生之旅(四):K8s 工作负载完全指南
  • 论文阅读笔记——自注意力机制
  • Xsens动作捕捉系统:训练、实时控制机器人
  • iOS 26 性能监控工具有哪些?多工具协同打造全方位性能分析体系
  • 做网站公司合同最新网站建设进程
  • 佳木斯做网站公司wordpress模板视频教程
  • viewerjs+vue3 using javascript