这是一个很久之前的问题了,今天记录一下,以便遇到同样问题的同学能够看到此文章

崩溃环境:

目前仅收到 windows 7 的部分用户反馈,在程序启动时发生闪退

问题分析:

查看用户提供的日志,可以看见崩溃发生在 sentry 内部

堆栈显示,在加载 sentry_get_modules_list 时程序出现闪退,已知 sentry_get_modules_list 是 sentry 源码里可找到的函数

p.s.  sentry_capture_event 是 sentry 内部上传日志所调用的函数,sentry_unwind_stack_from_ucontext 没有在源码中找到,所以姑且跳过这个函数

我们猜测是 sentry 在加载模块时出错了,于是我们便尝试将加载模块的部分代码先注释,再看会不会闪退

sentry_value_t
sentry_get_modules_list(void)
{
sentry__mutex_lock(&g_mutex);
if (!g_initialized) {
// load_modules(); // 这块先注释掉
g_initialized = true;
}
sentry_value_t modules = g_modules;
sentry_value_incref(modules);
sentry__mutex_unlock(&g_mutex);
return modules;
}

发现问题确实是出现 load_modules 里面,继续看 load_modules 内部干了啥,

static void
load_modules(void)
{
HANDLE snapshot
= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32W module = { 0 };
module.dwSize = sizeof(MODULEENTRY32W);
g_modules = sentry_value_new_list(); if (Module32FirstW(snapshot, &module)) {
do {
HMODULE handle = LoadLibraryExW(
module.szExePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
MEMORY_BASIC_INFORMATION vmem_info = { 0 };
if (handle
&& sizeof(vmem_info)
== VirtualQuery(
module.modBaseAddr, &vmem_info, sizeof(vmem_info))
&& vmem_info.State == MEM_COMMIT) {
sentry_value_t rv = sentry_value_new_object();
sentry_value_set_by_key(
rv, "type", sentry_value_new_string("pe"));
sentry_value_set_by_key(rv, "image_addr",
sentry__value_new_addr((uint64_t)module.modBaseAddr));
sentry_value_set_by_key(rv, "image_size",
sentry_value_new_int32((int32_t)module.modBaseSize));
sentry_value_set_by_key(rv, "code_file",
sentry__value_new_string_from_wstr(module.szExePath));
extract_pdb_info((uintptr_t)module.modBaseAddr, rv);
sentry_value_append(g_modules, rv);
}
FreeLibrary(handle);
} while (Module32NextW(snapshot, &module));
}

结合堆栈显示的 dll 信息,

(No symbol) [nvd3d9wrap.dll 0x000024DD]

问题可能在 sentry 调用 LoadLibraryExW 加载 nvd3d9wrap.dll 时崩溃了,我们尝试在遍历 dll 时跳过它,并在测试机器上测试,发现仍然闪退

那问题出在哪里呢?

google 了一下,看是否有类似案例,查到了一个 bug 反馈

- https://bugzilla.mozilla.org/show_bug.cgi?id=1607574

关键部分:

sentry 加载 detoured.dll 时调到了映射地址,在该地址上继续加载 nvd3d9wrap.dll,从而发生了崩溃

对此,我们尝试跳过 detoured.dll 的加载,程序没闪退

解决方案:

1. 只对 win7 之前的 windows 机器(包括 win7)做判断

2. 如果机器加载到 detoured.dll,则跳过该 dll 的加载

代码:

#define STATUS_SUCCESS (0x00000000)
typedef NTSTATUS (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); bool
GetRealOSVersion(RTL_OSVERSIONINFOW *provi)
{
HMODULE hMod = GetModuleHandleW(L"ntdll.dll");
if (hMod) {
RtlGetVersionPtr fxPtr
= (RtlGetVersionPtr)GetProcAddress(hMod, "RtlGetVersion");
if (fxPtr) {
if (STATUS_SUCCESS == fxPtr(provi)) {
return true;
}
}
}
return false;
} bool
IsWin8OrGreater()
{
bool is_win7_or_greater = true;
bool is_win8_or_greater = false; OSVERSIONINFOEX ver = {0};
ver.dwOSVersionInfoSize = sizeof(ver); if (VerifyVersionInfo(&ver,
VER_MAJORVERSION | VER_MINORVERSION | VER_PRODUCT_TYPE, NULL)) {
is_win7_or_greater = (ver.dwMajorVersion > 6)
|| ((ver.dwMajorVersion == 6) && (ver.dwMinorVersion >= 1));
is_win8_or_greater = (ver.dwMajorVersion > 6)
|| ((ver.dwMajorVersion == 6) && (ver.dwMinorVersion > 1));
} if (is_win7_or_greater) {
RTL_OSVERSIONINFOW rovi = {0};
rovi.dwOSVersionInfoSize = sizeof(rovi);
if (GetRealOSVersion(&rovi)) {
is_win8_or_greater = (rovi.dwMajorVersion > 6)
|| ((rovi.dwMajorVersion == 6) && (rovi.dwMinorVersion > 1));
}
} return is_win8_or_greater;
} static void
load_modules(void)
{
HANDLE snapshot
= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32W module = {0};
module.dwSize = sizeof(MODULEENTRY32W);
g_modules = sentry_value_new_list(); /* 部分 win7 电脑在加载 nvd3d9wrap.dll 会出现闪退,故跳过该部分代码 */
/* https://bugzilla.mozilla.org/show_bug.cgi?id=1607574 */
bool is_win8_or_later = IsWin8OrGreater();
if (Module32FirstW(snapshot, &module)) {
do {
if (!is_win8_or_later) {
wchar_t *wstr_copy;
if (_wcslwr_s(wstr_copy = _wcsdup(module.szModule),
wcslen(module.szModule) + 1)
== 0) {
if (wcscmp(wstr_copy, L"detoured.dll") == 0) {
free(wstr_copy);
continue;
}
free(wstr_copy);
}
} HMODULE handle = LoadLibraryExW(
module.szExePath, NULL, LOAD_LIBRARY_AS_DATAFILE);
MEMORY_BASIC_INFORMATION vmem_info = { 0 };
...

sentry 在加载模块时闪退的更多相关文章

  1. 内核加载模块时提示usb_common: exports duplicate symbol of_usb_get_dr_mode

    1.分析: 既然符号重复了,那么说明有一个部分既被编译到内核中也被编译成模块了,因此在加载模块时,内核报符号重复的提示 2.解决 直接配置内核的某一部分编译成模块,例如笔者就直接将USB这一部分编译成 ...

  2. 内核加载模块时出现Unknown symbol等提示

    一.背景 1.更改了内核的配置,重新编译了内核 2.未重新编译内核模块 3.板子上只更新了内核,并未更新文件系统 二.分析 发现是在加载内核模块时出现Unknown symbol等信息,恰逢当时只更新 ...

  3. 在加载模块时出现cannot insert '*.ko': Device or resource busy错误

    制作了一个模块,在加载是出现了cannot insert '*.ko': Device or resource busy错误. 原因: 是由于模块使用的是静态分配设备号,而这个设备号已经被系统中的其他 ...

  4. ios wkwebview 跳转到新的controllerview加载页面 出现闪退问题

    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { if(isF ...

  5. 加载驱动模块时Device or resource busy的解决方法

    加载驱动模块时Device or resource busy的解决方法 加载驱动模块时Device or resource busy的解决方法 insmod或modprobe驱动模块时Device o ...

  6. Linux驱动之内核加载模块过程分析

    Linux内核支持动态的加载模块运行:比如insmod first_drv.ko,这样就可以将模块加载到内核所在空间供应用程序调用.现在简单描述下insmod first_drv.ko的过程 1.in ...

  7. [driver]linux内核动态加载模块

    问题: 1. 把编译好的模块放到板子/lib/modules对应文件夹下,并且执行了depmod -a, 比如pl2303.ko, 那么下一次插入pl2303的串口线,是否可以识别,也就是自动加载pl ...

  8. Linux中实现在系统启动时自动加载模块

    下面是以前学习Linux时写的,后来仔细研究rc.sysinit后发现,只需要修改下列地方就可以了,不必这么麻烦的: rc.sysinit中有这样的一段代码: # Load other user-de ...

  9. 嵌入式 Linux 与linux启动时自动加载模块

    一.在ARM linux 下,一般而言,产品在启动的过程中应该加载模块,最简单的方法是修改启动过程的rc脚本(/etc/init.d/rcS),增加ismod /../xxx.ko这个命令.例如:加载 ...

  10. AngularJS中多个ng-app(手动加载模块)

    1.当有多个ng-app时:(首先是要加载angularJS) <div ng-app=""> <p>姓名:<input type="tex ...

随机推荐

  1. [转帖]如何监控Redis性能指标(译)

    Redis给人的印象是简单.很快,但是不代表它不需要关注它的性能指标,此文简单地介绍了一部分Redis性能指标.翻译过程中加入了自己延伸的一些疑问信息,仍然还有一些东西没有完全弄明白.原文中Metri ...

  2. [转帖]看看 Jmeter 是如何玩转 redis 数据库的

    柠檬小欧 2021-08-31 20:06420 Jmeter 作为当前非常受欢迎的接口测试和性能测试的工具,在企业中得到非常广泛的使用,而 Redis 作为缓存数据库,也在企业中得到普遍使用,那如何 ...

  3. [转帖]@Autowired 和 @Resource 的区别

    @Autowired 和 @Resource 的区别 默认注入方式不同 @Autowired 默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口 ...

  4. ESXi上面虚拟机磁盘损坏修复案例

    事故情况 最近同事反馈, 一个文件更新后出现了文件部分不可读的情况 具体现象为: 前端功能打开白屏 后端文件 前面93行不显示, notepad++打开都是 NULL 黑框. 然后重新覆盖文件, 有概 ...

  5. 2024了,我不想再用AOP收集业务操作日志了 | 京东云技术团队

    0.背景 在近期的项目中,系统涉及到针对系统的业务操作日志统计功能,由于本系统位于业务链路的中心环节,负责接收上游系统的数据,并将基于用户操作产生的数据传递至下游系统,鉴于业务链路的复杂性和操作场景的 ...

  6. 京东云开发者|提高IT运维效率,深度解读京东云AIOps落地实践

    基于深度学习对运维时序指标进行异常检测,快速发现线上业务问题 时间序列的异常检测是实际应用中的一个关键问题,尤其是在 IT 行业.我们没有采用传统的基于阈值的方法来实现异常检测,而是通过深度学习提出了 ...

  7. css3写一个加载动画

    先制作一个正方形,让圆点在正方形的最外侧 <style> body { margin: 0; } .loading { width: 200px; height: 200px; backg ...

  8. 清空elementui让计数器input-number的默认值

    <el-form-item label="考试时长:" prop="testTimeLong"> <el-input-number style ...

  9. 在Protocol Buffers中导入当前目录中的.proto文件

    在protobuf中导入当前目录中的.proto文件时,可以使用相对路径.相对路径是相对于当前.proto文件所在的目录来引用其他.proto文件. 假设有以下目录结构: my_project/ |- ...

  10. 使用CSS3实现鼠标移到图片上图片放大

    转自 http://www.webkaka.com/tutorial/html/2017/072731/ 在现在的网页设计中,鼠标移到图片上图片放大的效果常常被用到,这个效果多应用于文章列表里.我一开 ...