如何从 EXC_BAD_ACCESS 中恢复?

2023-12-27

我是故意造成的EXC_BAD_ACCESS。通过触发写入NSObject在只读虚拟内存页中。理想情况下,我想抓住EXC_BAD_ACCESS,将虚拟内存页标记为可读写,并像平常一样继续执行。这可能吗?我编写的代码导致EXC_BAD_ACCESS在下面。

WeakTargetObject.h (ARC)

@interface WeakTargetObject : NSObject
@property (nonatomic, weak) NSObject *target;
@end

WeakTargetObject.m (ARC)

@implementation WeakTargetObject
@end

main.m (MRR)

- (void)main {
  char *mem = NULL;
  vm_allocate(mach_task_self(), (vm_address_t *)&mem, vm_page_size, VM_FLAGS_ANYWHERE);
  NSLog(@"mem: %p", mem);
  WeakTargetObject *weakTargetObject = objc_constructInstance([WeakTargetObject class], (void *)mem);

  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSObject *target = [[NSObject alloc] init];
  weakTargetObject.target = target;
  [pool drain];
  pool = [[NSAutoreleasePool alloc] init];
  NSLog(@"expect non-nil. weakTargetObject.target: %@", weakTargetObject.target);
  [pool drain];

  vm_protect(mach_task_self(),
             (vm_address_t)mem,
             vm_page_size,
             1,
             VM_PROT_READ);

  // triggers EXC_BAD_ACCESS when objc runtime 
  // tries to nil weakTargetObject.target
  [weakTargetObject release]; 
  NSLog(@"expect nil. weakTargetObject.target: %@", weakTargetObject.target);
}

我找到了一个达尔文开发帖子 http://lists.apple.com/archives/darwin-dev/2006/Oct/msg00122.html这就是答案!

WARNING

这个答案有一个很大的缺点。我的调试器无法在除 mach 异常线程之外的任何线程中工作。在任何其他线程中放置断点都会导致 Xcode5 挂起。我不得不强行退出它。在我的里面catch_exception_raise功能,效果很好。我向 LLDB 的人询问了这个问题。 http://lists.cs.uiuc.edu/pipermail/lldb-dev/2013-October/002596.html

结束警告

这段代码是答案的骨架。它将无限循环,因为(根据跟进 http://lists.apple.com/archives/darwin-dev/2006/Oct/msg00136.html)您需要采取一些措施来使错误恢复。就我而言,我需要将页面标记为读写。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#include <pthread.h>
#include <assert.h>
#include <mach/mach.h>

kern_return_t
catch_exception_raise(mach_port_t exception_port,
                      mach_port_t thread,
                      mach_port_t task,
                      exception_type_t exception,
                      exception_data_t code_vector,
                      mach_msg_type_number_t code_count)
{
    fprintf(stderr, "catch_exception_raise %d\n", exception);
    return KERN_SUCCESS;  // loops infinitely...
}

void *exception_handler(void *arg)
{
    extern boolean_t exc_server();
    mach_port_t port = (mach_port_t) arg;
    mach_msg_server(exc_server, 2048, port, 0);
    abort(); // without this GCC complains (it doesn't know that mach_msg_server never returns)
}

void setup_mach_exception_port()
{
    static mach_port_t exception_port = MACH_PORT_NULL;
    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exception_port);
    mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
    task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
    pthread_t returned_thread;
    pthread_create(&returned_thread, NULL, exception_handler, (void*) exception_port);
}

void test_crash()
{
    id *obj = NULL;
    *obj = @"foo";
}

int main(int argc, char** argv)
{
    setup_mach_exception_port();
    test_crash();
    return 0;
}

这是我有效的新代码:

WeakTargetObject.h (ARC)

@interface WeakTargetObject : NSObject
@property (nonatomic, weak) NSObject *target;
@end

WeakTargetObject.m (ARC)

@implementation WeakTargetObject
@end

main.m (MRR)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#include <pthread.h>
#include <assert.h>
#include <mach/mach.h>

static char * mem = NULL;

kern_return_t
catch_exception_raise(mach_port_t exception_port,
                      mach_port_t thread,
                      mach_port_t task,
                      exception_type_t exception,
                      exception_data_t code_vector,
                      mach_msg_type_number_t code_count)
{
  fprintf(stderr, "catch_exception_raise %d, mem: %p\n", exception, mem);
  kern_return_t success = vm_protect(mach_task_self(),
                                     (vm_address_t)mem,
                                     vm_page_size,
                                     0,
                                     VM_PROT_DEFAULT);
  fprintf(stderr, "switched to read-write: %d\n", success);
  return KERN_SUCCESS;
}

void *exception_handler(void *arg)
{
    extern boolean_t exc_server();
    mach_port_t port = (mach_port_t) arg;
    mach_msg_server(exc_server, 2048, port, 0);
    abort(); // without this GCC complains (it doesn't know that mach_msg_server never returns)
}

void setup_mach_exception_port()
{
    static mach_port_t exception_port = MACH_PORT_NULL;
    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exception_port);
    mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
    task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
    pthread_t returned_thread;
    pthread_create(&returned_thread, NULL, exception_handler, (void*) exception_port);
}

- (void)main {
  setup_mach_exception_port();
  vm_allocate(mach_task_self(), (vm_address_t *)&mem, vm_page_size, VM_FLAGS_ANYWHERE);
  NSLog(@"mem: %p", mem);
  WeakTargetObject *weakTargetObject = objc_constructInstance([WeakTargetObject class], (void *)mem);

  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSObject *target = [[NSObject alloc] init];
  weakTargetObject.target = target;
  [pool drain];
  pool = [[NSAutoreleasePool alloc] init];
  NSLog(@"expect non-nil. weakTargetObject.target: %@", weakTargetObject.target);
  [pool drain];

  vm_protect(mach_task_self(),
             (vm_address_t)mem,
             vm_page_size,
             // zero means don't set VM_PROT_READ as the maximum protection
             // one means DO set VM_PROT_READ as the maximum protection
             // we want zero because the if VM_PROT_READ is the maximum protection
             // we won't be able to set it to VM_PROT_DEFAULT later
             0,
             VM_PROT_READ);

  // triggers EXC_BAD_ACCESS when objc runtime 
  // tries to nil weakTargetObject.target
  [weakTargetObject release]; 
  NSLog(@"expect nil. weakTargetObject.target: %@", weakTargetObject.target);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 EXC_BAD_ACCESS 中恢复? 的相关文章

  • 多次添加同一个子视图来查看

    我不知道这是否可行 但我想做的是将子视图多次添加到视图中 我尝试过这样的事情 self view addSubview newView newView center CGPointMake 160 100 self view addSubv
  • iOS - NSNotificationCenter 多个UIKeyboard通知

    我有两个视图控制器 我们称它们为 A 和 B 1 在 A 中 我显示一个包含文本字段的 popOver 2 B中有一个UITextView用于简单的文本编辑 我必须管理 A 和 B 中的键盘才能滚动键盘隐藏的内容 我知道如何重新定位内容 我
  • iOS Storyboards 我应该使用它们吗? [复制]

    这个问题在这里已经有答案了 我是 iOS 开发新手 尚未创建应用程序 但我向我的朋友寻求建议 他在市场上拥有非常高评价的应用程序 他说不要使用故事板 尽管我很想听取他的建议 但它们似乎确实很有帮助 这是否会在将来给我的应用程序带来问题 我有
  • 是什么导致了这个 iPhone 崩溃日志?

    我有点卡住了 需要解决这个问题 因为我的一个应用程序出现了随机崩溃 而这些崩溃并不总是能够重现 这是崩溃日志之一 Incident Identifier 59865612 9F00 44EA 9474 2BF607AD662E CrashR
  • 无法将 admob 与 firebase iOS/Android 项目链接

    我有两个帐户 A 和 B A 是在 Firebase 上托管 iOS Android unity 手机游戏的主帐户 B 用于将 admob 集成到 iOS Android 手机游戏中 我在尝试将 admob 分析链接到 Firebase 项
  • 如何在 Apple Watch Extension/App 和 iOS App 之间建立通信通道

    我正在探索 WatchKit SDK 当我有 WatchKit 应用程序时 是否可以在 WatchKit 应用程序上从 iPhone 应用程序设置值 例如文本 设置 我可以从 iPhone 应用程序调用 WatchKit 应用程序扩展中的函
  • 由于语言错误,Itunes Connect 无法提交

    Thats all it shows https i stack imgur com 0aZm8 png 我不确定它没有告诉我出了什么问题 it shows its linked to the language https i stack
  • 这个错误是无效上下文0x0吗?

    我在ViewDidLoad中编写了以下代码 Implement viewDidLoad to do additional setup after loading the view typically from a nib void view
  • 暂停视频录制[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在尝试创建一个应用程序 用户可以在其中从相机录制视频 该应用程序的功能之一必须是文件录制中的暂停 例如 用户通过按 开始 按钮开始
  • UITextFieldDelegate 与 UITextField 控件事件

    如果我想处理 UITextField 的更改 例如用户在其中键入 看起来这可以通过将委托分配给该文本字段 然后让委托实现 shouldChangeCharactersInRange 来完成 或者通过将目标添加到文本字段并处理 UIContr
  • ITMS-90535 无法使用最新的 Google Signin SDK 发布 iOS 应用程序

    我正在使用 xcode 7 GM 种子并通过 cocoapods 安装了最新的 Google Signin SDKpod Google SignIn 当我尝试将我的应用程序发布到苹果应用程序商店时 我收到附加错误 Help 以下是 Goog
  • 如何检测Retina高清显示屏?

    UIScreen有一个新的 nativeScaleiOS 8 中的属性 但文档没有提及它 property nonatomic readonly CGFloat nativeScale 还有一个scale属性 但文档说它是 2 用于视网膜显
  • iOS 8 中的 UISplitViewController 状态恢复

    在 iOS 8 上 UISplitViewController 似乎可以保存和恢复其子视图的状态 例如 主视图是否隐藏 这是不可取的 因为我的应用程序应该始终以横向方式显示主视图 并始终以纵向方式隐藏它 如果用户以横向模式关闭应用程序 保存
  • 如何请求用户开启定位服务

    我需要我的应用程序来访问用户的当前位置 它在应用程序开始时检查用户是否已设置 如果没有 我需要应用程序显示提示以使其使用位置服务 就像警报视图一样 点击按钮 它应该会带您进入 iPhone 上的位置服务屏幕 您可以通过以下代码检查 loca
  • PresentModalViewController 不执行任何操作

    我有一个 UIViewController parent 调用presentModalViewController与另一个 UIViewController child on viewDidLoad If parent没有 UINaviga
  • 混合静态和动态 UITableViewController 内容会导致 NSRangeException

    我一直在寻找这个错误 并找到了一些具有类似行为的帖子 但没有解决问题的解决方案 我有一个 UITableViewController 在 SB 中声明为静态 它具有以下部分 第 0 部分 配方 是静态的 有 4 个单元格 第 1 部分 口味
  • iPhone 快照,包括键盘

    我正在寻找拍摄整个 iPhone 屏幕 包括键盘 的正确方法 我找到了一些截取屏幕的代码 CGRect screenCaptureRect UIScreen mainScreen bounds UIView viewWhereYouWant
  • Objective C UIImagePNGRepresentation内存问题(使用ARC)

    我有一个基于 ARC 的应用程序 它从 Web 服务加载大约 2 000 个相当大 1 4MB 的 Base64 编码图像 它将 Base64 解码后的字符串转换为 png图像文件并将其保存到磁盘 这一切都是在一个循环中完成的 我不应该有任
  • 如何更改已上传的 Firebase 存储图像文件名?

    我需要更改已上传到 firebase 存储中的文件名 因为 在 firebase 存储中上传图像后 我将 url 保存在 firebase 数据库中的特定子 文件夹 下 但是 当我将图像移动到另一个子 文件夹 时 我需要根据新名称更改存储中
  • 将 iPhone 上的 stderr 写入文件和控制台

    我正在遵循答案中的建议here https stackoverflow com questions 5179108 iphone how to read application logs from device用于将 iOS 设备上的 NS

随机推荐