iOS開(kāi)發(fā)之Crash追蹤之旅(一)

序: 最近在日常開(kāi)發(fā)中遇到了一次Crash引起的Crash的血災(zāi),在5月初的一次發(fā)版把筆者開(kāi)發(fā)的App的Crash率直接從萬(wàn)一干到了接近千二冶共,當(dāng)時(shí)項(xiàng)目負(fù)責(zé)人正好需要向上報(bào)告項(xiàng)目QA相關(guān)情況比默,當(dāng)時(shí)就懵逼了??。

問(wèn)題

由于年初花了大功夫把原來(lái)OC為主體的項(xiàng)目完全遷移到Swift谐岁,由于Swift的安全性伊佃,crash保持的一直不錯(cuò)航揉,忽然這一出搞的也挺懵帅涂,查了一下UMeng的crash追蹤媳友,全是報(bào)Attempted to dereference garbage pointer 0x18ffd63d72d0醇锚,符號(hào)化之后的crash函數(shù)調(diào)用棧也挺迷的焊唬,在不定線程crash赶促,app的函數(shù)符號(hào)定位都是在一個(gè)模型類的0行。
整理了一下相關(guān)的crash log 和umeng上的用戶行為矩屁,知道應(yīng)該是碰到了內(nèi)存問(wèn)題或野指針了,這種傷腦的問(wèn)題如果只是幾個(gè)零星的crash就果斷放后面解決了空幻,但是千分之二的crash直接影響了飯碗問(wèn)題约郁,只能硬著頭皮去解決鬓梅,也是為了重塑曾今的那鐘對(duì)技術(shù)極致追求的精神绽快。

結(jié)果

在整理了Umeng的Crash Log和行為日志以及App Connent用戶上傳的Crash Log紧阔,可以確定是由于野指針/內(nèi)存問(wèn)題引起的隨機(jī)Crash坊罢,并且整理到以下線索

  • 隨機(jī)crash出現(xiàn)在app運(yùn)行5分鐘之后的占比很高
  • 剛冷啟動(dòng)時(shí)(用戶軌跡只有adviewcontroller)也會(huì)發(fā)生crash的,說(shuō)明有問(wèn)題的代碼應(yīng)該在啟動(dòng)那塊執(zhí)行
  • 和idfa的獲取方式變化有關(guān)擅耽,因?yàn)樾掳姹荆?.1.0)由于idfa政策變化被拒過(guò)活孩,因此可以定位到應(yīng)該是集團(tuán)提供的風(fēng)控SDK嫌疑很大,修改提審和風(fēng)控部門對(duì)過(guò)他們sdk有收集idfa乖仇,回憶在集成代碼的時(shí)候發(fā)現(xiàn)風(fēng)控sdk是使用c和c++開(kāi)發(fā)的憾儒,當(dāng)時(shí)改Swift集成的時(shí)候還因此加了橋接文件。
  • 在高版本iOS系統(tǒng)和新手機(jī)(arm64e)設(shè)備上搜集到的crash多航夺,低版本和高版本的原始crash的Exception Type是不一樣的:arm64e 是 SIGSEGV arm64 是 SIGBUS

在這里吐槽下Umeng的crash收集,沒(méi)有顯示原始的錯(cuò)誤崔涂,都?xì)w納為Attempted to dereference garbage pointer阳掐,不利于排查和定位錯(cuò)誤

解決步驟:

  1. 拉取2.1.0發(fā)版代碼
  2. xcode 打開(kāi) Address Sanitizer(Asan)重新編譯運(yùn)行 -> buggy address 的確可以查到有內(nèi)存使用問(wèn)題
  3. 注釋啟動(dòng)相關(guān)代碼 風(fēng)控sdk初始化代碼,發(fā)現(xiàn)的確是風(fēng)控sdk導(dǎo)致的
  4. 聯(lián)系風(fēng)控組,替換SDK缭保,通過(guò)測(cè)試
  5. 等待上線驗(yàn)證

到這里汛闸,這次Crash問(wèn)題告一段落了,但是在追蹤過(guò)程中查看和回歸了以前很多相關(guān)的底層技術(shù)和工具艺骂,在解決問(wèn)題后再次坐下深入的總結(jié)和記錄诸老。

涉及的技術(shù)點(diǎn)

  1. iOS內(nèi)存管理機(jī)制: OC C C++的這方面資料很多,可以拓展去看下Swift的坐下總結(jié)
  2. 符號(hào)文件解析, LLDB高級(jí)調(diào)試和插件編寫(xiě)钳恕,ASDN相關(guān)
  3. iOS系統(tǒng)crash:Exception(mach oc) 和 unix的bsd 的signal錯(cuò)誤
  4. bugly的apm工具原理和實(shí)現(xiàn)
  5. PAC(PAC技術(shù))[https://justinyan.me/post/4129]

我會(huì)以若干篇章去深入探索下相關(guān)技術(shù)點(diǎn)

iOS系統(tǒng)中的Crash

1. Crash的分類

記得在之前文章中探索過(guò)為什么移動(dòng)應(yīng)用會(huì)有crash:內(nèi)存管理别伏,因?yàn)橐苿?dòng)系統(tǒng)為了保護(hù)閃存而舍棄了Swap機(jī)制。

Crash的主要原因是App收到未處理的信號(hào)忧额,iOS的核心操作系統(tǒng)是Darwin厘肮,Darwin內(nèi)核是XNU("X is Not UNIX"),XNU是一個(gè)基于Mach+BSD的混合內(nèi)核睦番,所以引起Crash的信號(hào)可以分為三種:

  1. Mach異常:Mach負(fù)責(zé)XNU比較底層的任務(wù)类茂,所以Mach異常是指底層的內(nèi)核級(jí)異常,用戶態(tài)的開(kāi)發(fā)者可以直接通過(guò)Mach API設(shè)置thread托嚣、task和host的異常端口來(lái)捕獲Mach異常
  2. Unix信號(hào):又稱BSD信號(hào)(XNU中的BSD發(fā)出)巩检,如果開(kāi)發(fā)者沒(méi)有捕捉Mach異常,則會(huì)被host層的方法ux_exception()轉(zhuǎn)化為對(duì)應(yīng)的Unix信號(hào)示启,并通過(guò)threadsignal()將信號(hào)投遞到出錯(cuò)的線程兢哭,可以通過(guò)signal(x, SignalHandler)來(lái)捕獲signal
  3. NSException:應(yīng)用級(jí)異常,也可以認(rèn)為是OC語(yǔ)言層面的異常夫嗓,導(dǎo)致程序向自身發(fā)送了SIGABORT信號(hào)而crash厦瓢,可以try catch捕獲或者通過(guò)NSSetUncaughtExceptionHandler()機(jī)制來(lái)捕獲

Swift的異常機(jī)制這方面的大佬們分享的很少 ,可以研究下Swift的錯(cuò)誤機(jī)制

上面三個(gè)層面的Crash啤月,語(yǔ)言層面的(OC)應(yīng)用級(jí)的Crash是最好解決的,數(shù)組越界劳跃、 runtime的msg_send消息轉(zhuǎn)發(fā)機(jī)制導(dǎo)致的crash谎仲,kvc等OC語(yǔ)言機(jī)制的crash可以通過(guò)crash log中的backtrace很快定位到。而對(duì)于Mach異常和Unix信號(hào)導(dǎo)致的crash則對(duì)于高級(jí)開(kāi)發(fā)來(lái)說(shuō)也是很大的挑戰(zhàn)刨仑。

2. Mach異常和Unix信號(hào)

Mach異常是什么郑诺?它又是如何與Unix信號(hào)建立聯(lián)系的?

// crash log頭部
Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0022000000000000 -> 0x0000000000000000 (possible pointer authentication failure)
  1. Mach異常是XNU的微內(nèi)核核心Mach運(yùn)行中出現(xiàn)的內(nèi)核級(jí)異常杉武,每個(gè)thread辙诞、task、host(這個(gè)host是什么轻抱?)都有一個(gè)異常端口數(shù)組飞涂,Mach的部分API暴露給用戶態(tài),用戶態(tài)的開(kāi)發(fā)者可以直接通過(guò)Mach API設(shè)置thread、task较店、host的異常端口士八,來(lái)捕獲Mach異常。
  2. 所有未處理的Mach異常梁呈,都會(huì)通過(guò)ux_exception()轉(zhuǎn)化為Unix信號(hào)婚度,通過(guò)threadsignal將信號(hào)傳遞到出錯(cuò)的線程。iOS的POSIX API就是通過(guò)Mach上層的BSD層實(shí)現(xiàn)的官卡。

注:Mach 最基礎(chǔ)的對(duì)象是“主機(jī)(host)”蝗茁,也就是表示機(jī)器本身的對(duì)象

如上面的貼的Crash Log頭部摘自我這次Crash的日志,EXC_BAD_ACCESS(訪問(wèn)無(wú)效內(nèi)存)異常寻咒,因?yàn)闆](méi)有在Mach層捕獲哮翘,被host層轉(zhuǎn)化為SIGSEGV信號(hào)傳遞給了出錯(cuò)的線程。

所以:

  1. 未處理Mach異常是會(huì)轉(zhuǎn)為Unix Signal仔涩,應(yīng)用級(jí)異常未捕獲也會(huì)在轉(zhuǎn)為NSException, 然后調(diào)用C的Abort()忍坷,kernel對(duì)App發(fā)出__pthread_kill信號(hào),觸發(fā)Mach異常熔脂,所以只要未捕獲的異常都是會(huì)轉(zhuǎn)化為一條Unix信號(hào)佩研。
  2. 硬件產(chǎn)生的信號(hào)(通過(guò)CPU的trap機(jī)制:mach_msg_trap(),陷阱這個(gè)概念在 Mach 中等同于系統(tǒng)調(diào)用)被Mach捕獲霞揉,然后轉(zhuǎn)化為Unix信號(hào)旬薯。
  3. Apple為了統(tǒng)一機(jī)制,操作系統(tǒng)或者用戶產(chǎn)生的信號(hào)(kill和thread_kill)也會(huì)轉(zhuǎn)化為Mach異常适秩,最后轉(zhuǎn)為Unix信號(hào)绊序。
Crash產(chǎn)生原理和傳遞過(guò)程

4. Mach異常和Unix信號(hào)的分類

常見(jiàn)的Mach異常

  • EXC_CRASH: 進(jìn)程異常退出(SIGABORT) 或者 watch dog超時(shí)殺死App(SIGKILL)
  • EXC_BREAKPOINT (SIGTRAP)
  • EXC_BAD_ACCESS :內(nèi)存訪問(wèn)無(wú)效
  • EXC_BAD_INSTRUCTION:線程試圖訪問(wèn)非法/無(wú)效的指令或?qū)o(wú)效的參數(shù)(操作數(shù))傳遞給指令
  • EXC_ARITMETHIC:除以0或整數(shù)溢出/下溢引發(fā)的異常
  • EXC_SYSCALL 和 EXC_MACH_SYSCALL:應(yīng)用程序訪問(wèn)內(nèi)核服務(wù)(如文件I/O)或網(wǎng)絡(luò)訪問(wèn)時(shí)發(fā)出
  • 其他Mach異常定義在mach/exception_types.h中。與處理器相關(guān)的異常定義在mach/(i386,ppc,...)/exception.h中
    在開(kāi)發(fā)中最常見(jiàn)的異常應(yīng)該是EXC_BAD_ACCESS秽荞,就比如這次追蹤到的

Unix信號(hào)

信號(hào)處理函數(shù)可以通過(guò) signal() 系統(tǒng)調(diào)用來(lái)設(shè)置骤公。如果沒(méi)有為一個(gè)信號(hào)設(shè)置對(duì)應(yīng)的處理函數(shù),就會(huì)使用默認(rèn)的處理函數(shù)扬跋,否則信號(hào)就被進(jìn)程截獲并調(diào)用相應(yīng)的處理函數(shù)阶捆。在沒(méi)有處理函數(shù)的情況下,程序可以指定兩種行為:忽略這個(gè)信號(hào) SIG_IGN 或者用默認(rèn)的處理函數(shù) SIG_DFL 钦听。但是有兩個(gè)信號(hào)是無(wú)法被截獲并處理的: SIGKILL洒试、SIGSTOP 。

Signal信號(hào)類型:

  • SIGABRT--程序中止命令中止信號(hào)
  • SIGALRM--程序超時(shí)信號(hào)
  • SIGFPE--程序浮點(diǎn)異常信號(hào)
  • SIGILL--程序非法指令信號(hào)
  • SIGHUP--程序終端中止信號(hào)
  • SIGINT--程序鍵盤中斷信號(hào)
  • SIGKILL--程序結(jié)束接收中止信號(hào)
  • SIGTERM--程序kill中止信號(hào)
  • SIGSTOP--程序鍵盤中止信號(hào)
  • SIGSEGV--程序無(wú)效內(nèi)存中止信號(hào)
  • SIGBUS--程序內(nèi)存字節(jié)未對(duì)齊中止信號(hào)
  • SIGPIPE--程序Socket發(fā)送失敗中止信號(hào)

5. 模擬Mach Message發(fā)送和捕獲Mach異常

5.1 Mach

Mach是XNU的微內(nèi)核
Mach的幾個(gè)基本概念:
Tasks: 擁有一組系統(tǒng)資源的對(duì)象朴上,允許thread在其中執(zhí)行
Threads: 執(zhí)行的基本單位垒棋,擁有task的上下文,并共享其資源
Ports: task之間通訊的一組受保護(hù)的消息隊(duì)列痪宰,task可以對(duì)任何port發(fā)送/接收數(shù)據(jù)
Message:有類型的數(shù)據(jù)對(duì)象集合叼架,只可以發(fā)送給Host

5.2 模擬Mach Message的發(fā)送
  1. 創(chuàng)建 post 授權(quán)
+ (mach_port_t)createPortAndListener {
    // 在Mach的頭文件中找到的 mach_port_t 完全等價(jià)于 mach_port_name_t
    // typedef unsigned int            __darwin_natural_t;
    // typedef __darwin_natural_t __darwin_mach_port_name_t; /* Used by mach */
    // typedef __darwin_mach_port_name_t __darwin_mach_port_t; /* Used by mach */
    // typedef __darwin_mach_port_t mach_port_t;
    // typedef natural_t mach_port_name_t;
    // typedef __darwin_natural_t      natural_t;
    
    mach_port_t server_port;
    kern_return_t kr = mach_port_allocate(mach_task_self(),
                                          MACH_PORT_RIGHT_RECEIVE,
                                          &server_port);
    assert(kr == KERN_SUCCESS);
    
    NSLog(@"Create a port: %d", server_port);
    
    kr = mach_port_insert_right(mach_task_self(),
                                server_port,
                                server_port,
                                MACH_MSG_TYPE_MAKE_SEND);
    assert(kr == KERN_SUCCESS);
    
    return server_port;
}

  1. Mach 端口監(jiān)聽(tīng)
+ (void)setMachPortListener:(mach_port_t)mach_port {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        mach_msg_header_t mach_message;
        
        mach_message.msgh_size = 1024;
        mach_message.msgh_local_port = mach_port;
        
        mach_msg_return_t mr;
        
        while (true) {
            mr = mach_msg(&mach_message,
                          MACH_RCV_MSG | MACH_RCV_LARGE,
                          0,
                          mach_message.msgh_size,
                          mach_message.msgh_local_port,
                          MACH_MSG_TIMEOUT_NONE,
                          MACH_PORT_NULL);
            if (mr != MACH_MSG_SUCCESS && mr != MACH_RCV_TOO_LARGE) {
                NSLog(@"error!");
            }
            
            mach_msg_id_t msg_id = mach_message.msgh_id;
            mach_port_t remote_port = mach_message.msgh_remote_port;
            mach_port_t local_port = mach_message.msgh_local_port;
            
            NSLog(@"Recevie a mach messag:[%d], remote_port: %d, local_port: %d, exception",
                  msg_id, remote_port, local_port);
        }
    });
}
  1. 向創(chuàng)建的 mach port 發(fā)送消息
+ (void)sendMachPostMessage:(mach_port_t)mach_port {
    kern_return_t kr;
    mach_msg_header_t msg_header;
    msg_header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
    msg_header.msgh_size = sizeof(mach_msg_header_t);
    msg_header.msgh_remote_port = mach_port;
    msg_header.msgh_local_port = MACH_PORT_NULL;
    msg_header.msgh_id = 100;
    NSLog(@"Send a mach message: [%d]", msg_header.msgh_id);
    
    kr = mach_msg(&msg_header,
                  MACH_SEND_MSG,
                  msg_header.msgh_size,
                  0,
                  MACH_PORT_NULL,
                  MACH_MSG_TIMEOUT_NONE,
                  MACH_PORT_NULL);
}

5.3 在Mach層捕獲異常

6. Signal注冊(cè)和處理

7.PAC

在這次的Crash追溯的過(guò)程中畔裕,我發(fā)現(xiàn):

  1. 在比較新的機(jī)器上(一般iOS系統(tǒng)版本也比較高), Crash的概率比較大
  2. 通過(guò)App Connect搜集到的原始Crash Log中Crash的Mach異常轉(zhuǎn)化后的Signal是不一樣的

比較老設(shè)備收集到的Crash Log頭部:Unix Signal -> SIGBUS

//  比較老的手機(jī):iPhone 8
Incident Identifier: 9DCFF105-1CBE-4947-B386-68E4375EC340
Hardware Model:      iPhone10,1
Process:             esport-app [15056]
Path:                /private/var/containers/Bundle/Application/86BE49B4-3975-45D9-AC97-CD9CABF4F7D0/esport-app.app/esport-app
Identifier:          com.wmzq.esportapp
Version:             2 (2.1.0)
AppStoreTools:       12E262
AppVariant:          1:iPhone10,1:13
Beta:                YES
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           com.wmzq.esportapp [2538]


Date/Time:           2021-05-06 15:08:30.2709 +0800
Launch Time:         2021-05-06 15:08:28.6146 +0800
OS Version:          iPhone OS 13.7 (17H35)
Release Type:        User
Baseband Version:    5.70.01
Report Version:      104

Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: KERN_PROTECTION_FAILURE at 0x000000016c1bfdc0
VM Region Info: 0x16c1bfdc0 is in 0x16c1bc000-0x16c1c0000;  bytes after start: 15808  bytes before end: 575
      REGION TYPE                      START - END             [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      Stack                  000000016c0ec000-000000016c1bc000 [  832K] rw-/rwx SM=COW  thread 21
--->  STACK GUARD            000000016c1bc000-000000016c1c0000 [   16K] ---/rwx SM=NUL  ...for thread 22
      Stack                  000000016c1c0000-000000016c248000 [  544K] rw-/rwx SM=COW  thread 22

Termination Signal: Bus error: 10
Termination Reason: Namespace SIGNAL, Code 0xa
Terminating Process: exc handler [15056]
Triggered by Thread:  22

新設(shè)備收集到的Crash Log頭部:Unix Signal -> SIGSEGV

// iPhone XR
Incident Identifier: 95414C75-D357-4AFC-9951-2EAE098F31B3
Hardware Model:      iPhone11,8
Process:             esport-app [13681]
Path:                /private/var/containers/Bundle/Application/07BF60A9-D0A0-4B29-A9F2-C5E6C99D84EC/esport-app.app/esport-app
Identifier:          com.wmzq.esportapp
Version:             2105031 (2.1.0)
AppStoreTools:       12E262
AppVariant:          1:iPhone11,8:14
Beta:                YES
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           com.wmzq.esportapp [742]


Date/Time:           2021-05-08 09:41:52.5606 +0800
Launch Time:         2021-05-08 08:38:34.2531 +0800
OS Version:          iPhone OS 14.5 (18E199)
Release Type:        User
Baseband Version:    3.03.05
Report Version:      104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0022000000000000 -> 0x0000000000000000 (possible pointer authentication failure)
VM Region Info: 0 is not in any region.  Bytes before following region: 4373348352
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                   104ac0000-104b24000 [  400K] r-x/r-x SM=COW  ...pp/esport-app

Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [13681]
Triggered by Thread:  11

通過(guò)查閱資料知道了Apple在A12開(kāi)始支持了arm64e指令集,提供了指令地址加密功能碉碉,即PAC(Pointer Authentication Code的縮寫(xiě))

7.1 PAC是什么

PAC是ARMv8.3 新增的功能柴钻,因?yàn)殡m然系統(tǒng)是64位的,但是arm64指令地址根本用不滿垢粮,所以把高位的部分(upper bits)拿來(lái)存一個(gè)指針地址的簽名贴届。
PAC指針驗(yàn)證碼就是在CPU執(zhí)行指令前先拿指針的高位簽名和低位的實(shí)際地址部分坐下校驗(yàn),失敗了直接拋出異常
為了實(shí)現(xiàn)PAC, arm64e新增了兩個(gè)指令:

  • PACIASP 計(jì)算 PAC 加密并加到指針地址上
  • AUTIASP 校驗(yàn)加密部分蜡吧,并還原指針地址
7.2 PAC應(yīng)用舉例

在這里我主要記錄了下這次Cras追溯的過(guò)程和總結(jié)了下iOS系統(tǒng)Crash的產(chǎn)生原理毫蚓,Crash從內(nèi)核態(tài) -> 拋出至用戶態(tài)的過(guò)程,以及PAC等一些概念性的東西昔善。
后面的幾篇文章我會(huì)總結(jié)Xcode的內(nèi)存診斷工具元潘,Zombie Objects、 Address Sanitizer君仆、Malloc Scribble的原理和使用翩概,盡量通過(guò)代碼和WoWCrash示例去實(shí)現(xiàn)一個(gè)搜集定位內(nèi)存問(wèn)題的APM工具。

好久沒(méi)有好好的深入研究一些技術(shù)了返咱,之前一度認(rèn)為iOS的技術(shù)深入不劃算了钥庇,現(xiàn)今的開(kāi)發(fā)都是頁(yè)面黨,替代性太強(qiáng)了咖摹,所以一直猶豫是否轉(zhuǎn)后端或者web评姨。但這次的Crash追蹤過(guò)程,讓我覺(jué)得成為相關(guān)方面資深開(kāi)發(fā)甚至專家對(duì)我還是有誘惑力的萤晴,從Crash Log分析->逆向工具使用->底層原理認(rèn)知->解決問(wèn)題獲取那種喜悅吐句,讓我重新找回方向,加油店读,走出舒適區(qū)??嗦枢。

參考資料

iOS Mach 異常、Unix 信號(hào) 和NSException 異常
iOS Mach異常和signal信號(hào)
為什么 arm64e 的指針地址有空余支持 PAC屯断?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末文虏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子裹纳,更是在濱河造成了極大的恐慌,老刑警劉巖紧武,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剃氧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡阻星,警方通過(guò)查閱死者的電腦和手機(jī)朋鞍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門已添,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人滥酥,你說(shuō)我怎么就攤上這事更舞。” “怎么了坎吻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵缆蝉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瘦真,道長(zhǎng)刊头,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任诸尽,我火速辦了婚禮原杂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘您机。我一直安慰自己穿肄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布际看。 她就那樣靜靜地躺著咸产,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仿村。 梳的紋絲不亂的頭發(fā)上锐朴,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音蔼囊,去河邊找鬼焚志。 笑死,一個(gè)胖子當(dāng)著我的面吹牛畏鼓,可吹牛的內(nèi)容都是我干的酱酬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼云矫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼膳沽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起让禀,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤挑社,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后巡揍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體痛阻,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年腮敌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阱当。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俏扩。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弊添,靈堂內(nèi)的尸體忽然破棺而出录淡,到底是詐尸還是另有隱情,我是刑警寧澤油坝,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布嫉戚,位于F島的核電站,受9級(jí)特大地震影響免钻,放射性物質(zhì)發(fā)生泄漏彼水。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一极舔、第九天 我趴在偏房一處隱蔽的房頂上張望凤覆。 院中可真熱鬧,春花似錦拆魏、人聲如沸盯桦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拥峦。三九已至,卻和暖如春卖子,著一層夾襖步出監(jiān)牢的瞬間略号,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工洋闽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玄柠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓诫舅,卻偏偏與公主長(zhǎng)得像羽利,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刊懈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容