美文网首页
使用->访问实例对象成员变量Crash问题

使用->访问实例对象成员变量Crash问题

作者: 小米咸鱼 | 来源:发表于2021-06-21 14:44 被阅读0次

使用->访问实例对象成员变量Crash问题

前言

最近线上发生了一个Crash。根据栈信息定位到如下代码
EXC_BAD_ACCESS (SIGBUS)
Attempted to dereference garbage pointer 0x10. Originated at or in a subcall of WebViewJavascriptBridge_js
if (instance->ivar) {
    ...
}

就是访问成员变量时Crash。

难道instance可能为空,但是为空应该也不会Crash吧?因为在我的固有的思维里面,对nil发送消息并不会crash。
但是又仔细想了想,访问成员变量时,是通过当前类的实例对象偏移量再加上此变量在类中的偏移量获取的。与发送消息无关(不是属性,没有写get方法)。如果当前实例对象如果为空(obj的offet=0),为什么还会继续呢?百思不得解。
写了一个demo,使用clang命令转换为cpp文件后,才知道缘由。
大体代码如下:
//MyObject.h
@interface MyObject : NSObject {
    @public
    NSString    *_strObject;
    NSArray     *_arrList;
}
@end
//Test.h
@implementation Test

- (void)helloworld {
    MyObject *obj = nil;
    if (condition) {
        obj = [MyObject new];
    }
    NSString *str = obj->_strObject;
    NSLog(@"%@", str);
}

@end
clang -rewrite-objc Test.m
通过clang命令获取Test.cpp文件(10万行左右)
在后面看到如下片段
#pragma clang assume_nonnull end
// @implementation Test


static void _I_Test_helloworld(Test * self, SEL _cmd) {
    MyObject *obj = __null;
    if (condition) {
        obj = ((MyObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MyObject"), sel_registerName("new"));
    }
    NSString *str = (*(NSString **)((char *)obj + OBJC_IVAR_$_MyObject$_strObject));
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_hs_pl2pwmlj27g9xt0wlb9mbdbh0000gn_T_Test_2546e4_mi_0, str);
}

// @end

主要下这行代码

NSString *str = (*(NSString **)((char *)obj + OBJC_IVAR_$_MyObject$_strObject));

这段代码就是获取strObject偏移量,OBJC_IVAR_MyObject_strObject是一个在编译器已经决定了的固定的偏移量。obj就是实例对象的首地址。通过2个值获取到_strObject地址。如果obj==nil;这个偏移地址就是一个固定的值0,加上变量固定偏移量,值就类似于0x10(这也和crash信息里相匹配)。

结论
通过->访问成员变量要判断当前变量是否为空。通过offset寻址成员变量时并不会多一层为空判断逻辑。

文章转自:https://jackthenoob.github.io/2019/05/22/%E4%BD%BF%E7%94%A8-%E8%AE%BF%E9%97%AE%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%E6%88%90%E5%91%98%E5%8F%98%E9%87%8FCrash%E9%97%AE%E9%A2%98/

相关文章

  • 使用->访问实例对象成员变量Crash问题

    使用->访问实例对象成员变量Crash问题 [https://jackthenoob.github.io/2019...

  • java之了解

    访问实例变量和方法 通过已创建的对象来访问成员变量和成员方法,如下所示: /* 实例化对象*/ ObjectRef...

  • 1.3 静态成员

    基本概念 java类中的成员(变量和方法)分为两类: 实例成员,必须通过对象实例去访问,对于实例变量,每个对象都有...

  • 成员变量 局部变量 全局变量

    成员变量 写在类声明的大括号中的变量,我们称之为成员变量(属性、实例变量) 成员变量只能通过对象访问 成员变量不能...

  • JAVA(三)回忆基础扫盲之一

    一.对象与类 简单的类 实例化构造方法 访问实例化变量和访问成员方法使用get和set方法 二.JAVA的数据类型

  • Object-C中成员变量、全局变量和局部变量的区别

    一、成员变量 写在类声明的大括号中的变量,称之为成员变量(属性,实例变量) 成员变量只能通过对象来访问 成员变量不...

  • 实例变量和属性变量的比较

    导言 实例变量和属性变量的使用 当在对象之外使用实例变量时,我们通过属性来访问。但当我们在对象之内使用实例变量时,...

  • 局部变量和全局变量以及成员变量的区别

    成员变量写在类声明的大括号中的变量, 我们称之为 成员变量(属性, 实例变量)成员变量只能通过对象来访问注意: 成...

  • iOS的KVC底层原理(源码分析)

    先了解成员变量、属性、实例变量 实例变量: class类进行实例化出来的对象为实例对象。成员变量: 在{ }中所声...

  • 类方法和实例方法的区别

    类方法和实例方法 1、类方法是属于整个类,而不属于某个对象。2、类方法只能访问类成员变量,不能访问实例变量,而实例...

网友评论

      本文标题:使用->访问实例对象成员变量Crash问题

      本文链接:https://www.haomeiwen.com/subject/sfyyyltx.html