我的理解是,一般来说,如果从信号处理程序调用非异步信号安全函数,行为是不确定的,但我听说linux允许你安全地调用任何系统调用.这是真的?此外,SIGSEGV处理程序的唯一可移植行为是中止或退出,但我知道如果你返回,linux实际上会恢复执行,是吗?
我正在编写一个框架来实现在模拟器和未修改的主机软件中运行的RTL的协同仿真.编写主机软件以控制实际硬件,通常以两种方式之一工作:
前一种情况非常简单 - 编写一个库,它实现与驱动程序相同的读/写调用,并在运行模拟时与之相关联.这一切都非常有效,我可以运行未经修改的生产软件作为我的RTL模拟的刺激.
第二种情况比第一种情况要困难得多......
最初我以为我可以LD_PRELOAD用来拦截mmap调用.在我的实现中,mmap我会分配一些页面对齐的内存,然后mprotect设置一个信号处理程序来捕获SIGSEGV.
这种方法存在许多问题:
读取与写入
我可以确定访问的地址,siginfo_t->si_addr但不能确定访问是读还是写.
捕获重复访问
在信号处理程序中,我需要取消保护内存区域,否则SIGSEGV只要我的处理程序退出并且主机代码永远不会继续,我就会重复.但是,如果我取消保护区域,那么我的信号处理程序将不会捕获后续访问.
信号处理程序的肮脏
在模拟器驱动RTL并返回结果时阻塞信号处理程序违反了各种编程规则 - 特别是假设模拟器可以触发各种其他事件并在从此访问返回结果之前执行任意代码.
我想知道是否可以创建一个类似文件的对象,其行为类似于磁盘,而不是mprotect在缓冲区上使用.我没有找到任何表明这是可行的信息.
是否可以捕获对mmap区域的所有访问以及如何?
假设LD_PRELOAD并且mprotect是最佳路线:
mprotect该区域?我正在玩弄使用虚拟内存系统的想法,允许我对我得到的一些数字数据进行透明数据转换(例如int to float).基本思想是我正在编写的库mmaps您想要的数据文件,同时mmaps一个适当大小的匿名区域来保存转换后的数据,并将此指针返回给用户.
匿名区域的读/写保护,所以,每当用户经历的指针来访问数据,每一个新的页面会造成段错误,我能赶上,然后透明地在mmaped文件转换数据,同时设置权限允许访问继续.到目前为止,整个事情的这一部分很有效.
但是,有时我会绘制非常大的文件(数百GB),并且匿名内存代理访问它,很快你就会开始吃掉交换空间,因为匿名页面会被丢弃到磁盘上.我的想法是,如果我可以在将转换后的数据写入它们之后将匿名页面上的脏位显式设置为false,那么操作系统只会删除它们,并在以后重新访问时按需填充零.
对于这个工作,虽然,我想我必须设置脏位为假,并说服OS设置页面进行阅读时,他们交换出去的保护,这样我就可以重新赶上随后的段错误,并重新转换数据一经请求.在做了一些研究后,我认为没有内核黑客攻击是不可能的,但我想我会问,看看有更多关于虚拟内存系统的人是否知道可以实现的方法.
我试图在我的Android NDK应用程序中捕获SIGSEGV等信号以进行调试.为此,我设置了一个名为的sigaction.
我现在正试图获得通话的堆栈.问题是_Unwind_Backtrace只能在当前堆栈和sigaction上运行它自己的堆栈.
那么,有没有办法获得接收信号的执行指针的堆栈?(基本上告诉_Unwind_Backtrace放松另一个堆栈而不是当前?)
我应该指出:
使用backtrace()和backtrace_symbols()不是选项,因为这些功能未在Android NDK中提供
我正在使用GDB来调查本地设备上的崩溃.我不想替换GDB,我希望能够在向他发送测试版本时从客户端接收有意义的堆栈跟踪.
编辑:使用Android的libcorkscrew从系统/核心所建议的法登,但是当我使用它的unwind_backtrace_signal_arch功能,我得到一个奇怪的回溯不代表死机我都试过了.
首先:这个问题已经被问了几次,有些答案很有用,但没有一个提供有效的解决方案.我开始尝试这个答案的代码.令人惊讶的是,它做了它的事情,但是有一个很大的问题:调用这个代码的唯一方法我可以想到的是SIGSEGV处理程序,它有自己的堆栈 - 因此我无法得到我崩溃的应用程序的实际堆栈就像那样.
然后,我尝试合并这个答案.它稍微好一点 - 它产生堆栈的第一项(发生崩溃的方法).但那是 - 没有实际的回溯.因此,只要崩溃发生在第三方库(或标准库)中,此信息就毫无意义.
如何进一步改进代码并最终获得我糟糕的崩溃应用程序的堆栈跟踪?
PS在Android 4.0.3和Android 5.0上测试过,到目前为止行为是一样的.我想支持至少5.0和最近的早期版本,如4.3-4.4.
我有大量的数据存储在一个文件中.这个文件是mmap,但我随时只访问少量数据.我想了解我的程序的访问模式,以便我可以优化数据的排序(以便经常访问数据被分组到相同的页面中).目标是减少mmaped文件的工作集.
所以,我正在考虑使用R/W映射文件禁用.每次读/写尝试都会导致SEGV.在我的SEGV处理程序中,我将记录访问地址并允许程序继续.
我可以在错误地址处解码指令,并模拟其动作(通过相应地修改目标寄存器和存储器位置).
但是,我在某处读到Linux无法从SEGV中恢复.这是真的?当我的信号处理程序被调用时,我如何向操作系统表明"一切都很好,请在故障指令后立即继续"?
请注意,我不希望它重做错误指令,因为我会模拟它.
我现在只关心x86/x64架构.
谢谢!
这更像是一种哲学类型的问题.
在C++中,我们有很好的闪亮成语 - RAII.但我常常认为它不完整.它与我的应用程序可以用SIGSEGV杀死的事实不太一致.
我知道,我知道,像你这样的程序是不正确的.但令人遗憾的是,在POSIX(特别是Linux)上,您可以分配超出物理内存限制并在执行过程中满足SIGSEGV,使用正确分配的内存.
你可能会说:"应用程序死了,你为什么要关心那些没有被调用的糟糕的析构函数?".遗憾的是,有些资源在应用程序终止时不会自动释放,例如文件系统实体.
我现在非常厌倦了设计黑客,破坏良好的应用程序设计以应对这一点.所以,我要问的是为这类问题提供一个漂亮,优雅的解决方案.
似乎我错了,Linux应用程序被内核寻呼机杀死.在这种情况下,问题仍然是相同的,但申请死亡的原因是不同的.
代码段:
struct UnlinkGuard
{
UnlinkGuard(const std::string path_to_file)
: _path_to_file(path_to_file)
{ }
~UnlinkGuard() {
unlink();
}
bool unlink() {
if (_path_to_file.empty())
return true;
if (::unlink(_path_to_file.c_str())) {
/// Probably some logging.
return false;
}
disengage();
return true;
}
void disengage() {
_path_to_file.clear();
}
private:
std::string _path_to_file;
};
void foo()
{
/// Pick path to temp file.
std::string path_to_temp_file = "...";
/// …Run Code Online (Sandbox Code Playgroud) 我是一个C假人,正在研究一个C项目,它要求我编写一个信号处理程序来捕获SIGSEGV信号并执行一些操作.
基本上,主程序将尝试访问既不可读也不可写的内存块.当主程序访问这块内存时,它将引发一个SIGSEGV信号,在我的信号处理函数中,我将捕获信号并使用mprotect()将该内存块转换为可读写.
但我不知道有没有办法得到信号被我的信号处理程序捕获时导致SIGSEGV的地址.如果我没有导致SIGSEGV的实际地址,我什么也做不了.并且我不允许从main获取地址到我的信号处理程序.
有人能帮我吗?谢谢!
我的代码中有一些函数会随机导致SegmentationFault错误。我通过启用faulthandler. 我有点卡住了,不知道如何可靠地消除这个问题。
我正在考虑一些解决方法。由于函数随机崩溃,我可能会在失败后重试它们。问题是没有办法从SegmentationFault崩溃中恢复。
我现在最好的想法是稍微重写这些函数并通过子进程运行它们。此解决方案将帮助我,崩溃的函数不会使整个应用程序崩溃,并且可以重试。
一些功能非常小并且经常执行,因此它会显着降低我的应用程序的速度。是否有任何方法可以在单独的上下文中执行函数,比在出现段错误时不会使整个程序崩溃的子进程更快?
在C++中,是否有标准方法(或任何其他方式)来捕获由内存访问冲突触发的异常?
例如,如果出现问题且程序试图访问不应该访问的内容,您将如何收到错误消息,显示"内存访问违规!" 而不只是终止进程而不是向用户显示有关崩溃的任何信息?
我正在使用MinGW为Windows编写游戏,如果这有帮助的话.
在我的Android OpenGL ES项目中,我最近在着色器代码中出现错误,这显然在此处的OpenGL线程中引起了“致命信号11(SIGSEGV)”:
GLES32.glCompileShader(glShaderHandle);
Run Code Online (Sandbox Code Playgroud)
我解决了该错误,它再次正常运行,但是我很难找出该错误的出处。当然,我尝试像这样“捕获”着色器错误:
GLES32.glGetShaderiv(glShaderHandle, GLES32.GL_COMPILE_STATUS, result, 0);
Run Code Online (Sandbox Code Playgroud)
但是在发生SIGSEGV错误的情况下,Java代码甚至都没有达到这一点。另外尝试使用try / catch捕获错误也没有用。该应用程序仍然崩溃。我猜错误发生在本机C代码中。
有没有办法处理来自Java代码的此类错误,以防止应用程序崩溃?
c ×4
linux ×4
android ×3
c++ ×3
signals ×3
android-ndk ×2
mmap ×2
stack-trace ×2
backtrace ×1
exception ×1
java ×1
memoization ×1
opengl-es ×1
posix ×1
python ×1
python-3.8 ×1
python-3.x ×1
raii ×1
system-calls ×1
trace ×1
try-catch ×1