iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?

1、引言

相信大家都遇到过一段特殊文本可以让iOS设备所有app闪退的经历。前段时间大年初一,又出现某个印度语字符引起iOS11系统奔溃,所幸iOS版微信客户端做了保护并没有引起太大问题(字符处理这类技术问题,其实曾在Android版微信上导致过严重的用户体验危机。

一般来说,特殊字符闪退是系统漏洞引起,只要更新系统就行。但大部分用户不愿意更新系统,而苹果也不一定第一时间解决问题。另外后台可以拦截恶意文本传递,但对于本地已下发的消息,后台没有办法让它删除。所以客户端还是要做些保护预防特殊字符闪退。

2、微信的思路

由于无法事先知道字符串里包含特殊字符,所以只能先让它排版/绘制,看看是否出现问题。做法是,在排版/绘制字符串前,先设置标记位,排版/绘制结束后,移除标记位。

一旦发现标记位存在,就意味着这字符串可能有问题,下次就不显示这个字符串:

这里有几个问题:

有可能在排版/绘制过程中,其它线程crash,导致标记位不能正常移除。所以crash时要判断crash线程是否为排版/绘制线程。

究竟crash多少次才能判断这字符串是有问题的:最早做法是crash一次就直接屏蔽,但很多用户反馈,说某些好友昵称无法显示。其实iOS绘制字符串时也会极少概率出现闪退,从而误判。但crash两次才屏蔽的话,如果用户连续收到N条恶意消息,那么至少crash 2N次才彻底把所有有问题消息屏蔽。

因此,第一次字符串crash先不屏蔽,后续连续字符串crash的话,直接屏蔽。这样crash N+1次就能处理完了。

3、具体的iOS代码实现

正如第2节的思路那样。整个逻辑代码大致如下。

MessageItemView.mm:

//CP是CrashProtected的简称

@implementationMessageItemView

- (void)initContentLabel {

m_label = [[MMCPLabel alloc] init];

m_label.cpKey = [MMCPUtil generateKeyWithObject:self.messageModel];

if([MMCPUtil isUnsafeWithKey:m_label.cpKey]) {

// 检测出messageModel消息内容有问题,屏蔽显示

m_label.text = @"该内容无法显示";

} else{

m_label.text = self.messageModel.content;

}

}

@end

MMCPLabel.mm:

@implementationMMCPLabel

@synthesizecpKey = m_cpKey;

// 对常用的排版/绘制接口做检查

- (void)layoutSublayersOfLayer:(CALayer *)layer {

CScopedCrashCounter crashCounter(m_cpKey);

[superlayoutSublayersOfLayer:layer];

}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {

CScopedCrashCounter crashCounter(m_cpKey);

[superdrawLayer:layer inContext:ctx];

}

- (CGSize)sizeThatFits:(CGSize)size {

CScopedCrashCounter crashCounter(m_cpKey);

return[supersizeThatFits:size];

}

@end

MMCPUtil.mm:

// 利用C++特性,在声明C++类临时变量时,会自动执行构造函数,离开作用域会执行析构函数

// 因此构造函数做crashCount+1,析构函数做crashCount-1

classCScopedCrashCounter {

public:

CScopedCrashCounter(NSString*cpKey) {

m_cpKey = cpKey;

[MMCPUtil increaseCrashCountWithKey:m_cpKey];

}

~CScopedCrashCounter() {

[MMCPUtil decreaseCrashCountWithKey:m_cpKey];

}

private:

NSString*m_cpKey;

};

@implementationMMCPUtil

@synthesizecrashKeyMemoryMappedKV = m_crashKeyMemoryMappedKV; // 被判定为恶意信息对应的key

@synthesizecrashCountMemoryMappedKV = m_crashCountMemoryMappedKV; // 每个key crash次数

- (BOOL)isUnsafeWithKey:(NSString*)key {

return[m_crashKeyMemoryMappedKV getBoolForKey:key] == YES;

}

- (void)increaseCrashCountWithKey:(NSString*)key {

// 这里记录key所在线程

...

int32_t count = [m_crashCountMemoryMappedKV getInt32ForKey:key];

[m_crashCountMemoryMappedKV setInt32:count + 1 forKey:key]

}

- (void)decreaseCrashCountWithKey:(NSString*)key {

int32_t count = [m_crashCountMemoryMappedKV getInt32ForKey:key];

[m_crashCountMemoryMappedKV setInt32:MAX(0, count - 1) forKey:key];

}

// crash回调函数

- (void)onSignalCrash:(siginfo_t *)info {

// 先找到跟crash线程相同的key

NSString*key = [selflastCPKey:info->si_pid];

if(key == nil) return;

if(m_isLastTimeCrashedBySpecialCharacter == NO) {

// 设置当前是特殊字符引起的闪退,如果crash次数大于1,则屏蔽这字符串显示

[selfsetLastTimeCrashedBySpecialCharacter:YES];

if([m_crashCountMemoryMappedKV getInt32ForKey:key] > 1) {

[m_crashKeyMemoryMappedKV setBool:YESforKey:key];

}

} else{

// 连续特殊字符闪退,直接屏蔽

[m_crashKeyMemoryMappedKV setBool:YESforKey:key];

}

}

@end

4、还需要从用户体验上做更进一步改进

即使有了上面的N+1优化,当N很大时,客户端还是要crash很多次才能正常使用。之前有用户乱扫二维码被拉进炸群,如果不发红包,群主不停炸群;用户频繁crash,也无法退群。不少用户会选择卸载重装客户端。因此客户端要加上安全模式的机制。

当客户端检测出连续三次crash,下次启动会出现安全模式的界面,提示用户如何处理:

对于频繁闪退的群聊,主界面提供快捷入口方便用户退群。另外对于可能误判的字符串,界面也提供入口方便用户恢复字符串显示:

为了让后台第一时间发现新的特殊字符变种,客户端检测出特殊字符crash后,会把相关信息上报到后台。通过客户端上报、后台拦截的闭环,能大大降低特殊字符传播范围。这方案不仅用于特殊字符,还能用于其他恶意信息,如炸群消息、GIF、小视频、链接等。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容

  • 前言 最先接触编程的知识是在大学里面,大学里面学了一些基础的知识,c语言,java语言,单片机的汇编语言等;大学毕...
    oceanfive阅读 3,055评论 0 7
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,139评论 30 470
  • 转自http://www.raywenderlich.com/zh-hans/30818/ios应用崩溃日志揭秘 ...
    RunSnails阅读 4,431评论 2 22
  • 闵杏郁,温州圣卡萝服饰有限公司;63期同修、79期志工、116期志工、160期志工、203期志工、224期志工【日...
    杏郁阅读 250评论 0 0
  • 凭空不见愁绪满天,花开自落佛门无过 安然问己何处归去?踌渡三生河苦无文三钱 待情郎,望我可怜处给予艄公今生舵 默默...
    谁家璧人阅读 187评论 12 0