iOS Crash監(jiān)測(cè)及處理上傳

前段時(shí)間做了下項(xiàng)目里面的crash監(jiān)測(cè)(自己攔截監(jiān)測(cè)锅睛,不是bugly那些東西)咙好,然后保存crash信息乎澄,同步給服務(wù)器酌泰,進(jìn)行crashlog解析漠畜,這里總結(jié)下相關(guān)的流程和知識(shí)點(diǎn)曹洽。后面會(huì)有完整demo致燥。

一、概念性東西

符號(hào)表

1赂韵、概念:符號(hào)表就是指在Xcode項(xiàng)目編譯后娱节,在編譯生成的.app的同級(jí)目錄下生成的同名的.dSYM文件。
.dSYM文件其實(shí)是一個(gè)目錄祭示,在子目錄中包含了一個(gè)16進(jìn)制的保存函數(shù)地址映射信息的中轉(zhuǎn)文件括堤,所有Debug的symbols都在這個(gè)文件中(包括文件名、函數(shù)名绍移、行號(hào)等)悄窃,所以也稱之為調(diào)試符號(hào)信息文件。
2蹂窖、作用:符號(hào)表就是用來(lái)符號(hào)化 crash log(崩潰日志)轧抗。crash log中有一些方法16進(jìn)制的內(nèi)存地址等,通過(guò)符號(hào)表就能找到對(duì)應(yīng)的能夠直觀看到的方法名之類瞬测。
3横媚、獲取途徑:在Archive的時(shí)候會(huì)生成.xcarchive文件,然后顯示包內(nèi)容就能夠在里面找到.dsYM文件和.app文件月趟。

二灯蝴、Crash捕獲

iOS端的crash分為兩類,一類是NSException異常孝宗,另外一類是Signal信號(hào)異常穷躁。這兩類異常我們都可以通過(guò)注冊(cè)相關(guān)函數(shù)來(lái)捕獲。

1因妇、NSException異常捕獲

NSException異常是OC代碼導(dǎo)致的crash问潭,我們可以先調(diào)用NSGetUncaughtExceptionHandler獲取之前注冊(cè)的handler,如果有就保存起來(lái)婚被,再通過(guò)NSSetUncaughtExceptionHandler方法注冊(cè)自己的handler狡忙。

NSUncaughtExceptionHandler *OldHandler = nil;
void RegisterExceptionHandler(void) {
    if (NSGetUncaughtExceptionHandler() != MyExceptionHandler) {
        OldHandler = NSGetUncaughtExceptionHandler();
    }
    NSSetUncaughtExceptionHandler(&MyExceptionHandler);
}

注意:這里需要保存之前注冊(cè)的handler的原因是,很多第三方SDK都會(huì)集成一個(gè)Crash收集服務(wù)址芯,以及時(shí)發(fā)現(xiàn)自己SDK的問(wèn)題灾茁。當(dāng)各家的服務(wù)都以保證自己的Crash統(tǒng)計(jì)正確完整為目的時(shí),難免出現(xiàn)時(shí)序手腳谷炸,強(qiáng)行覆蓋等等的惡意競(jìng)爭(zhēng)北专,總會(huì)有人默默被坑。
如果同時(shí)有多方通過(guò)NSSetUncaughtExceptionHandler注冊(cè)異常處理程序淑廊,和平的作法是:后注冊(cè)者通過(guò)NSGetUncaughtExceptionHandler將先前別人注冊(cè)的handler取出并備份逗余,在自己handler處理完后自覺把別人的handler注冊(cè)回去,規(guī)規(guī)矩矩的傳遞季惩。不傳遞強(qiáng)行覆蓋的后果是录粱,在其之前注冊(cè)過(guò)的日志收集服務(wù)寫出的Crash日志就會(huì)因?yàn)槿〔坏絅SException而丟失Last Exception Backtrace等信息腻格。(P.S. iOS系統(tǒng)自帶的Crash Reporter不受影響)

下面附上MyExceptionHandler的實(shí)現(xiàn)

NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";
//oc exception
void MyExceptionHandler(NSException *exception) {
    NSArray *callStack = exception.callStackSymbols;
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
    [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];

    [[[GHCrashManager alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:[NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo] waitUntilDone:YES];
    
    // 調(diào)用之前已經(jīng)注冊(cè)的handler
    if (OldHandler) {
        OldHandler(exception);
    }
}

在這里就已經(jīng)拿到了異常的NSException *exception對(duì)象,然后將里面的信息取出來(lái)做本地保存即可啥繁。

2菜职、Signal異常

使用Objective-C的異常處理是不能得到signal的,如果要處理它旗闽,我們還要利用unix標(biāo)準(zhǔn)的signal機(jī)制酬核。
Signal信號(hào)是由iOS底層mach信號(hào)異常轉(zhuǎn)換后以signal信號(hào)拋出的異常。既然是兼容posix標(biāo)準(zhǔn)的異常适室,我們可以通過(guò)sigaction函數(shù)以及signal函數(shù)注冊(cè)對(duì)應(yīng)的信號(hào)嫡意。
這里會(huì)有兩種實(shí)現(xiàn):
第一種:采用signal函數(shù)進(jìn)行信號(hào)捕獲(這里只注冊(cè)了部分常見的信號(hào))

void RegisterSignalHandler(void) {
    signal(SIGHUP, SignalHandler);
    signal(SIGINT, SignalHandler);
    signal(SIGQUIT, SignalHandler);
    signal(SIGABRT, SignalHandler);
    signal(SIGILL, SignalHandler);
    signal(SIGSEGV, SignalHandler);
    signal(SIGFPE, SignalHandler);
    signal(SIGBUS, SignalHandler);
    signal(SIGPIPE, SignalHandler);
}

接下來(lái)附上獲取到信號(hào)后的實(shí)現(xiàn):

void SignalHandler(int signal) {
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey];
    NSArray *callBack = [GHCrashManager backtrace];
    [userInfo setObject:callBack forKey:UncaughtExceptionHandlerAddressesKey];
    
    NSException *signalException = [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName reason:[NSString stringWithFormat:@"Signal %d was raised.",signal] userInfo:userInfo];
    [[[GHCrashManager alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:signalException waitUntilDone:YES];
}

第二種:采用sigaction函數(shù)進(jìn)行信號(hào)捕獲

void (*OldAbrtSignalHandler)(int, struct __siginfo *, void *);
void RegisterSignalHandler(void) {
    struct sigaction old_action;
    sigaction(SIGABRT, NULL, &old_action);
    if (old_action.sa_flags & SA_SIGINFO) {
        if (old_action.sa_sigaction != MySignalHandler) {
            OldAbrtSignalHandler = old_action.sa_sigaction;
        }
    }

    struct sigaction action;
    action.sa_sigaction = MySignalHandler;
    action.sa_flags = SA_NODEFER | SA_SIGINFO;
    sigemptyset(&action.sa_mask);
    sigaction(SIGABRT, &action, 0);
}

這里同樣做了保存先前別人注冊(cè)的handler。

static void MySignalHandler(int signal, siginfo_t* info, void* context) {
    SignalHandler(signal);
    
    // 處理前者注冊(cè)的 handler
    if (signal == SIGABRT) {
        if (OldAbrtSignalHandler) {
            OldAbrtSignalHandler(signal, info, context);
        }
    }
}

簡(jiǎn)單說(shuō)一下sigaction和signal函數(shù)的區(qū)別:
Linux主要有兩個(gè)函數(shù)實(shí)現(xiàn)信號(hào)的安裝登記:signal和sigaction捣辆。其中signal在系統(tǒng)調(diào)用的基礎(chǔ)上實(shí)現(xiàn)蔬螟,是庫(kù)函數(shù)。它只有兩個(gè)參數(shù)汽畴,不支持信號(hào)傳遞信息旧巾,主要是用于前32個(gè)非實(shí)時(shí)信號(hào)的安裝;而sigaction是較新的函數(shù)(由兩個(gè)系統(tǒng)調(diào)用實(shí)現(xiàn):sys_signal以及sys_rt_sigaction)忍些,有三個(gè)參數(shù)鲁猩,支持信號(hào)傳遞信息,主要用來(lái)與sigqueue系統(tǒng)調(diào)用配合使用罢坝。當(dāng)然廓握,sigaction同樣支持非實(shí)時(shí)信號(hào)的安裝,sigaction優(yōu)于signal主要體現(xiàn)在支持信號(hào)帶有參數(shù)炸客,而signal使用簡(jiǎn)單疾棵,如果沒有復(fù)雜使用場(chǎng)景可以直接使用signal函數(shù)戈钢。

附上大部分信號(hào)的說(shuō)明:

  1. SIGHUP
    本信號(hào)在用戶終端連接(正潮韵桑或非正常)結(jié)束時(shí)發(fā)出, 通常是在終端的控制進(jìn)程結(jié)束時(shí), 通知同一session內(nèi)的各個(gè)作業(yè), 這時(shí)它們與控制終端不再關(guān)聯(lián)。
    登錄Linux時(shí)殉了,系統(tǒng)會(huì)分配給登錄用戶一個(gè)終端(Session)开仰。在這個(gè)終端運(yùn)行的所有程序,包括前臺(tái)進(jìn)程組和后臺(tái)進(jìn)程組薪铜,一般都屬于這個(gè) Session众弓。當(dāng)用戶退出Linux登錄時(shí),前臺(tái)進(jìn)程組和后臺(tái)有對(duì)終端輸出的進(jìn)程將會(huì)收到SIGHUP信號(hào)隔箍。這個(gè)信號(hào)的默認(rèn)操作為終止進(jìn)程谓娃,因此前臺(tái)進(jìn) 程組和后臺(tái)有終端輸出的進(jìn)程就會(huì)中止。不過(guò)可以捕獲這個(gè)信號(hào)蜒滩,比如wget能捕獲SIGHUP信號(hào)滨达,并忽略它奶稠,這樣就算退出了Linux登錄, wget也 能繼續(xù)下載捡遍。
    此外锌订,對(duì)于與終端脫離關(guān)系的守護(hù)進(jìn)程,這個(gè)信號(hào)用于通知它重新讀取配置文件画株。
  2. SIGINT
    程序終止(interrupt)信號(hào), 在用戶鍵入INTR字符(通常是Ctrl-C)時(shí)發(fā)出辆飘,用于通知前臺(tái)進(jìn)程組終止進(jìn)程。
  3. SIGQUIT
    和SIGINT類似, 但由QUIT字符(通常是Ctrl-)來(lái)控制. 進(jìn)程在因收到SIGQUIT退出時(shí)會(huì)產(chǎn)生core文件, 在這個(gè)意義上類似于一個(gè)程序錯(cuò)誤信號(hào)谓传。
  4. SIGILL
    執(zhí)行了非法指令. 通常是因?yàn)榭蓤?zhí)行文件本身出現(xiàn)錯(cuò)誤, 或者試圖執(zhí)行數(shù)據(jù)段. 堆棧溢出時(shí)也有可能產(chǎn)生這個(gè)信號(hào)蜈项。
  5. SIGTRAP
    由斷點(diǎn)指令或其它trap指令產(chǎn)生. 由debugger使用。
  6. SIGABRT
    調(diào)用abort函數(shù)生成的信號(hào)续挟。
  7. SIGBUS
    非法地址, 包括內(nèi)存地址對(duì)齊(alignment)出錯(cuò)战得。比如訪問(wèn)一個(gè)四個(gè)字長(zhǎng)的整數(shù), 但其地址不是4的倍數(shù)。它與SIGSEGV的區(qū)別在于后者是由于對(duì)合法存儲(chǔ)地址的非法訪問(wèn)觸發(fā)的(如訪問(wèn)不屬于自己存儲(chǔ)空間或只讀存儲(chǔ)空間)庸推。
  8. SIGFPE
    在發(fā)生致命的算術(shù)運(yùn)算錯(cuò)誤時(shí)發(fā)出. 不僅包括浮點(diǎn)運(yùn)算錯(cuò)誤, 還包括溢出及除數(shù)為0等其它所有的算術(shù)的錯(cuò)誤常侦。
  9. SIGKILL
    用來(lái)立即結(jié)束程序的運(yùn)行. 本信號(hào)不能被阻塞、處理和忽略贬媒。如果管理員發(fā)現(xiàn)某個(gè)進(jìn)程終止不了聋亡,可嘗試發(fā)送這個(gè)信號(hào)。
  10. SIGUSR1
    留給用戶使用
  11. SIGSEGV
    試圖訪問(wèn)未分配給自己的內(nèi)存, 或試圖往沒有寫權(quán)限的內(nèi)存地址寫數(shù)據(jù).
  12. SIGUSR2
    留給用戶使用
  13. SIGPIPE
    管道破裂际乘。這個(gè)信號(hào)通常在進(jìn)程間通信產(chǎn)生坡倔,比如采用FIFO(管道)通信的兩個(gè)進(jìn)程,讀管道沒打開或者意外終止就往管道寫脖含,寫進(jìn)程會(huì)收到SIGPIPE信號(hào)罪塔。此外用Socket通信的兩個(gè)進(jìn)程,寫進(jìn)程在寫Socket的時(shí)候养葵,讀進(jìn)程已經(jīng)終止征堪。
  14. SIGALRM
    時(shí)鐘定時(shí)信號(hào), 計(jì)算的是實(shí)際的時(shí)間或時(shí)鐘時(shí)間. alarm函數(shù)使用該信號(hào).
  15. SIGTERM
    程序結(jié)束(terminate)信號(hào), 與SIGKILL不同的是該信號(hào)可以被阻塞和處理。通常用來(lái)要求程序自己正常退出关拒,shell命令kill缺省產(chǎn)生這個(gè)信號(hào)佃蚜。如果進(jìn)程終止不了,我們才會(huì)嘗試SIGKILL着绊。
  16. SIGCHLD
    子進(jìn)程結(jié)束時(shí), 父進(jìn)程會(huì)收到這個(gè)信號(hào)谐算。
    如果父進(jìn)程沒有處理這個(gè)信號(hào),也沒有等待(wait)子進(jìn)程归露,子進(jìn)程雖然終止洲脂,但是還會(huì)在內(nèi)核進(jìn)程表中占有表項(xiàng),這時(shí)的子進(jìn)程稱為僵尸進(jìn)程剧包。這種情 況我們應(yīng)該避免(父進(jìn)程或者忽略SIGCHILD信號(hào)恐锦,或者捕捉它雇毫,或者wait它派生的子進(jìn)程,或者父進(jìn)程先終止踩蔚,這時(shí)子進(jìn)程的終止自動(dòng)由init進(jìn)程 來(lái)接管)棚放。
  17. SIGCONT
    讓一個(gè)停止(stopped)的進(jìn)程繼續(xù)執(zhí)行. 本信號(hào)不能被阻塞. 可以用一個(gè)handler來(lái)讓程序在由stopped狀態(tài)變?yōu)槔^續(xù)執(zhí)行時(shí)完成特定的工作. 例如, 重新顯示提示符
  18. SIGSTOP
    停止(stopped)進(jìn)程的執(zhí)行. 注意它和terminate以及interrupt的區(qū)別:該進(jìn)程還未結(jié)束, 只是暫停執(zhí)行. 本信號(hào)不能被阻塞, 處理或忽略.
  19. SIGTSTP
    停止進(jìn)程的運(yùn)行, 但該信號(hào)可以被處理和忽略. 用戶鍵入SUSP字符時(shí)(通常是Ctrl-Z)發(fā)出這個(gè)信號(hào)
  20. SIGTTIN
    當(dāng)后臺(tái)作業(yè)要從用戶終端讀數(shù)據(jù)時(shí), 該作業(yè)中的所有進(jìn)程會(huì)收到SIGTTIN信號(hào). 缺省時(shí)這些進(jìn)程會(huì)停止執(zhí)行.
  21. SIGTTOU
    類似于SIGTTIN, 但在寫終端(或修改終端模式)時(shí)收到.
  22. SIGURG
    有”緊急”數(shù)據(jù)或out-of-band數(shù)據(jù)到達(dá)socket時(shí)產(chǎn)生.
  23. SIGXCPU
    超過(guò)CPU時(shí)間資源限制. 這個(gè)限制可以由getrlimit/setrlimit來(lái)讀取/改變。
  24. SIGXFSZ
    當(dāng)進(jìn)程企圖擴(kuò)大文件以至于超過(guò)文件大小資源限制馅闽。
  25. SIGVTALRM
    虛擬時(shí)鐘信號(hào). 類似于SIGALRM, 但是計(jì)算的是該進(jìn)程占用的CPU時(shí)間.
  26. SIGPROF
    類似于SIGALRM/SIGVTALRM, 但包括該進(jìn)程用的CPU時(shí)間以及系統(tǒng)調(diào)用的時(shí)間.
  27. SIGWINCH
    窗口大小改變時(shí)發(fā)出.
  28. SIGIO
    文件描述符準(zhǔn)備就緒, 可以開始進(jìn)行輸入/輸出操作.
  29. SIGPWR
    Power failure
  30. SIGSYS
    非法的系統(tǒng)調(diào)用飘蚯。

其中要注意:

  • 在以上列出的信號(hào)中,程序不可捕獲福也、阻塞或忽略的信號(hào)有:SIGKILL,SIGSTOP
  • 不能恢復(fù)至默認(rèn)動(dòng)作的信號(hào)有:SIGILL,SIGTRAP
  • 默認(rèn)會(huì)導(dǎo)致進(jìn)程流產(chǎn)的信號(hào)有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
    默認(rèn)會(huì)導(dǎo)致進(jìn)程退出的信號(hào)有:
  • SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
  • 默認(rèn)會(huì)導(dǎo)致進(jìn)程停止的信號(hào)有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
  • 默認(rèn)進(jìn)程忽略的信號(hào)有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH
  • 此外局骤,SIGIO在SVR4是退出,在4.3BSD中是忽略暴凑;SIGCONT在進(jìn)程掛起時(shí)是繼續(xù)峦甩,否則是忽略,不能被阻塞现喳。

另:
在debug模式下凯傲,如果你觸發(fā)了signal崩潰,那么應(yīng)用會(huì)直接崩潰到主函數(shù)嗦篱,斷點(diǎn)都沒用冰单,此時(shí)沒有任何log信息顯示出來(lái),如果你想看log信息的話灸促,你需要在lldb中诫欠,拿SIGABRT來(lái)說(shuō)吧,敲入pro hand -p true -s false SIGABRT命令浴栽,不然你啥也看不到荒叼。或者也可以不連接xcode去run典鸡,如果你照著后面的crash捕獲后處理了的話被廓。

三、Crash捕獲之后的處理

拿到exception對(duì)象后椿每,做三件事:
1伊者、如果是debug環(huán)境下提示使用者;
2间护、將crash信息保存在本地;
3挖诸、移除自己的注冊(cè)操作汁尺;
(當(dāng)然還有4、下次啟動(dòng)上傳crashLog)多律。

1痴突、show出異常信息

貼視圖就不用說(shuō)了搂蜓,重點(diǎn)是要防止當(dāng)前線程掛掉,那么就得使用runloop了辽装。

#ifdef DEBUG
    NSString *message = [NSString stringWithFormat:@"抱歉帮碰,APP發(fā)生了異常,請(qǐng)與開發(fā)人員聯(lián)系拾积,點(diǎn)擊屏幕繼續(xù)并自動(dòng)復(fù)制錯(cuò)誤信息到剪切板殉挽。\n\n異常報(bào)告:\n異常名稱:%@\n異常原因:%@\n堆棧信息:%@\n", [exception name], [exception reason], stackInfo];
    NSLog(@"%@",message);
    [self showCrashToastWithMessage:message];//貼視圖去顯示,建議直接丟到window上

    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
    while (!self.dismissed) {
        for (NSString *mode in (__bridge NSArray *)allModes) {
            //為阻止線程退出拓巧,使用 CFRunLoopRunInMode(model, 0.001, false)等待系統(tǒng)消息斯碌,false表示RunLoop沒有超時(shí)時(shí)間
            CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
        }
    }
    CFRelease(allModes);


#endif
2、存儲(chǔ)就不說(shuō)了肛度,讀寫文件的事傻唾。
3、移除自己的注冊(cè)
NSSetUncaughtExceptionHandler(NULL);
    signal(SIGHUP, SIG_DFL);
    signal(SIGINT, SIG_DFL);
    signal(SIGQUIT, SIG_DFL);
    signal(SIGABRT, SIG_DFL);
    signal(SIGILL, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
    
    NSLog(@"%@",[exception name]);
    if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName]) {
        kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
    } else {
        [exception raise];
    }

到這里crash的捕獲和本地存儲(chǔ)都已經(jīng)ok了承耿,log也能上傳到服務(wù)器了冠骄,接下來(lái)就剩拿到log和dsym文件進(jìn)行符號(hào)化了。
如果你想了解crash的原理和根源加袋,建議讀讀漫談iOS Crash收集框架猴抹。
另外,

demo在這里锁荔,里面也附上了幾種常見crash的案例蟀给,結(jié)合案例測(cè)試下吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阳堕,一起剝皮案震驚了整個(gè)濱河市跋理,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恬总,老刑警劉巖前普,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異壹堰,居然都是意外死亡拭卿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門贱纠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)峻厚,“玉大人,你說(shuō)我怎么就攤上這事谆焊』萏遥” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)辜王。 經(jīng)常有香客問(wèn)我劈狐,道長(zhǎng),這世上最難降的妖魔是什么呐馆? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任肥缔,我火速辦了婚禮,結(jié)果婚禮上汹来,老公的妹妹穿的比我還像新娘续膳。我一直安慰自己,他們只是感情好俗慈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布姑宽。 她就那樣靜靜地躺著,像睡著了一般闺阱。 火紅的嫁衣襯著肌膚如雪炮车。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天酣溃,我揣著相機(jī)與錄音瘦穆,去河邊找鬼。 笑死赊豌,一個(gè)胖子當(dāng)著我的面吹牛扛或,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碘饼,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼熙兔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了艾恼?” 一聲冷哼從身側(cè)響起住涉,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钠绍,沒想到半個(gè)月后舆声,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柳爽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年媳握,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磷脯。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛾找,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出争拐,到底是詐尸還是另有隱情腋粥,我是刑警寧澤晦雨,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布架曹,位于F島的核電站隘冲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏绑雄。R本人自食惡果不足惜展辞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望万牺。 院中可真熱鬧罗珍,春花似錦、人聲如沸脚粟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)核无。三九已至扣唱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間团南,已是汗流浹背噪沙。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吐根,地道東北人正歼。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拷橘,于是被迫代替她去往敵國(guó)和親局义。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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