NDK crash(signal 11 (SIGSEGV)) 分析歷程

Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x72a2ab8f40 in tid 20224...

我們收到一個(gè)來自于Android11 的crash error??注盈,很少做NDK相關(guān)自晰,看得我一臉懵灶平。

11-17 22:25:55.604 10114 14417 20224 F libc : Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x72a2ab8f40 in tid 20224 (...), pid 14417 (roid.app.camera)
11-17 22:26:11.921 10114 20280 20280 F DEBUG : backtrace:
11-17 22:26:11.921 10114 20280 20280 F DEBUG : #00 pc 000000000036243c /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::GuardedCopy::Check(char const, void const, bool)+20) (BuildId: 4282922bc58d6d4ba18963d4940dba75)
11-17 22:26:11.921 10114 20280 20280 F DEBUG : #01 pc 0000000000364bd4 /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::GuardedCopy::ReleaseGuardedPACopy(char const, _JNIEnv, _jarray, void, int)+632) (BuildId: 4282922bc58d6d4ba18963d4940dba75)
11-17 22:26:11.921 10114 20280 20280 F DEBUG : #02 pc 000000000036438c /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::ReleasePrimitiveArrayElements(char const, art::Primitive::Type, _JNIEnv, _jarray, void, int)+712) (BuildId: 4282922bc58d6d4ba18963d4940dba75)

看trace是發(fā)生在了ReleasePrimitiveArrayElements砂客。Code 差不多是這樣的偿乖, 也就是ReleasePrimitiveArrayElements發(fā)現(xiàn)數(shù)組越界了僚焦。

{
    // jbyteArray data
    unsigned char *input = new unsigned char[len];
    env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte *>(input));

    ... // actions
    env->ReleaseByteArrayElements(data, reinterpret_cast<jbyte *>(input), 0);
}

當(dāng)然最開始我并不理解什么叫數(shù)組越界茶凳,本能先考慮的是择示,數(shù)組出問題了吧陨簇?是不是空的吐绵?

{
    if (data == nullptr || input == nullptr) {
        LOG("data == null or input == null");
        return;
    } 
}

那顯然呢一定是完全沒用啊??
其實(shí)如果你故意把它設(shè)置為null的時(shí)候你就會(huì)發(fā)現(xiàn)空指針的報(bào)錯(cuò)是signal 6,而且會(huì)直白地告訴你non-nullable argument was NULL河绽。

A/DEBUG: signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
A/DEBUG: Abort message: 'JNI DETECTED ERROR IN APPLICATION: non-nullable argument was NULL
in call to ReleaseByteArrayElements
from boolean ...(byte[], double, double, double, double)'
A/DEBUG: backtrace:
A/DEBUG: #00 pc 00000000000832a8 /apex/com.android.runtime/lib64/bionic/libc.so (abort+160) (BuildId: b0750023d0cf44584c064da02400c159)
A/DEBUG: #01 pc 00000000004ba634 /apex/com.android.runtime/lib64/libart.so (art::Runtime::Abort(char const)+2388) (BuildId: c79d8488d870b3079640a498165bbfd0)
A/DEBUG: #02 pc 000000000000b458 /system/lib64/libbase.so (android::base::LogMessage::~LogMessage()+580) (BuildId: 36cd125456a5320dd3dcb8cfbd889a1a)
A/DEBUG: #03 pc 0000000000378c18 /apex/com.android.runtime/lib64/libart.so (art::JavaVMExt::JniAbort(char const
, char const)+1584) (BuildId: c79d8488d870b3079640a498165bbfd0)
A/DEBUG: #04 pc 0000000000378e3c /apex/com.android.runtime/lib64/libart.so (art::JavaVMExt::JniAbortV(char const
, char const, std::__va_list)+108) (BuildId: c79d8488d870b3079640a498165bbfd0)
A/DEBUG: #05 pc 000000000036b264 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::AbortF(char const
, ...)+136) (BuildId: c79d8488d870b3079640a498165bbfd0)
A/DEBUG: #06 pc 00000000003754a8 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::CheckJNI::ReleasePrimitiveArrayElements(char const, art::Primitive::Type, _JNIEnv, _jarray, void, int)+1908) (BuildId: c79d8488d870b3079640a498165bbfd0)

所以排除了空指針的可能性

所以己单,好了,別猜了耙饰,來理解一下吧纹笼。
https://source.android.com/devices/tech/debug/native-crash

這個(gè)錯(cuò)誤叫:Execute-only memory violation (Android 10 only) 只執(zhí)行內(nèi)存違規(guī)

對于 Android 10 及更高版本中的 arm64,二進(jìn)制文件和庫的可執(zhí)行部分會(huì)映射到只執(zhí)行(不可讀裙豆颉)內(nèi)存廷痘,作為防范代碼重用攻擊的一種安全強(qiáng)化技術(shù)。通過在可執(zhí)行內(nèi)存中搜索已知函數(shù)件已,或通過在事先不了解內(nèi)存布局的情況下構(gòu)造小工具鏈笋额,可以使用讀取基元繞過地址空間布局隨機(jī)化 (ASLR)。通過將可執(zhí)行代碼標(biāo)記為不可讀篷扩,讀取基元將無法訪問可執(zhí)行內(nèi)存兄猩,從而使各種攻擊技術(shù)無法圖謀不軌。這不僅可以提高 ASLR 的有效性,而且可以提高控制流完整性 (CFI)枢冤,因?yàn)椴粫?huì)再向使用讀取基元的攻擊者透露有效目的地鸠姨。
將代碼設(shè)為不可讀會(huì)導(dǎo)致故意或意外讀入已標(biāo)記為只執(zhí)行的內(nèi)存段拋出 SIGSEGV,并且代碼為 SEGV_ACCERR淹真。這可能是因?yàn)殄e(cuò)誤讶迁、漏洞、混合了代碼的數(shù)據(jù)(例如文字池)或故意進(jìn)行的內(nèi)存自省導(dǎo)致的核蘸。
編譯器會(huì)假設(shè)代碼和數(shù)據(jù)不是混合在一起的巍糯,但是手寫程序集會(huì)導(dǎo)致出現(xiàn)問題。在許多情況下客扎,只需將常量移動(dòng)到 .data 部分鳞贷,即可解決這些問題。如果可執(zhí)行代碼段絕對有必要進(jìn)行代碼內(nèi)省虐唠,則應(yīng)首先調(diào)用 mprotect(2) 以將該代碼標(biāo)記為可讀,然后在操作完成后重新將該代碼標(biāo)記為不可讀惰聂。
Cause: execute-only (no-read) memory access error; likely due to data in .text.
您可以通過原因行將只執(zhí)行內(nèi)存違規(guī)與其他崩潰區(qū)分開來疆偿。
您可以使用 crasher xom 重現(xiàn)此類崩潰的實(shí)例。

我想你根本沒看懂吧搓幌?沒錯(cuò)因?yàn)槲易x了兩遍都覺得啥也沒懂杆故。

然后我接下來看見了這個(gè)
https://source.android.com/devices/tech/debug/execute-only-memory
本來好像看到了希望,但是它有個(gè)warning溉愁。說這個(gè)在Android 11上移除了处铛。

Important: XOM support has been removed in the upstream Linux kernel. XOM is only supported in Android 10 and has been removed in Android 11 and kernel changes removing it have been backported to 4.9, so the common kernel no longer supports XOM. More details on why XOM support was removed upstream can be found at PAN mitigation bypass

不出所料,即使disable execute-only at a module level 也完全不work拐揭。

// Android.mk
LOCAL_XOM := false

// Android.bp
cc_binary { // or other module types
   ...
   xom: false,
}

由于一開始沒有可復(fù)現(xiàn)的設(shè)備撤蟆,所以大多數(shù)情況都是根據(jù)log來猜測。終于在周末我拿到了可復(fù)現(xiàn)的設(shè)備堂污。才發(fā)現(xiàn)這個(gè)問題最直接的復(fù)現(xiàn)方法是:

$adb root
$adb remount
$adb shell setenforce 0
——> 表示關(guān)閉selinux防火墻, 權(quán)限問題家肯。
 
$adb shell
 
In the adb shell,
# stop
# setprop dalvik.vm.checkjni true
# setprop dalvik.vm.jniopts forcecopy
# start
 
(Device is rebooted)
$ adb shell getprop | grep "dalvik.vm.checkjni"[dalvik.vm.checkjni]: [true] (Check true)
——>啟動(dòng)JNI檢查,調(diào)試用
 
$ adb shell getprop | grep "dalvik.vm.jniopts"[dalvik.vm.jniopts]: [forcecopy] (Check forcecopy)
——>檢查數(shù)組越界

打開了CheckJNI來檢查JNI error
https://android-developers.googleblog.com/2011/07/debugging-android-jni-with-checkjni.html
當(dāng)然最重要的能夠復(fù)現(xiàn)問題的點(diǎn)是dalvik.vm.jniopts盟猖。
如果是warnonly實(shí)際上你是get不到crash的讨衣。所以要改成forcecopy。
setprop dalvik.vm.jniopts warnonly
這個(gè)點(diǎn)就涉及到ART 垃圾回收(GC)了式镐。https://source.android.com/devices/tech/dalvik/gc-debug

ART 有多個(gè)不同的 GC 方案反镇,涉及運(yùn)行不同的垃圾回收器。從 Android 8 (Oreo) 開始娘汞,默認(rèn)方案是并發(fā)復(fù)制 (CC)歹茶。另一個(gè) GC 方案是并發(fā)標(biāo)記清除 (CMS)。

并發(fā)復(fù)制 (CC):

并發(fā)復(fù)制 GC 的一些主要特性包括:

  1. CC 支持使用名為“RegionTLAB”的觸碰指針分配器。此分配器可以向每個(gè)應(yīng)用線程分配一個(gè)線程本地分配緩沖區(qū) (TLAB)辆亏,這樣风秤,應(yīng)用線程只需觸碰“棧頂”指針,而無需任何同步操作扮叨,即可從其 TLAB 中將對象分配出去缤弦。
  2. CC 通過在不暫停應(yīng)用線程的情況下并發(fā)復(fù)制對象來執(zhí)行堆碎片整理。這是在讀取屏障的幫助下實(shí)現(xiàn)的彻磁,讀取屏障會(huì)攔截來自堆的引用讀取碍沐,無需應(yīng)用開發(fā)者進(jìn)行任何干預(yù)。
  3. GC 只有一次很短的暫停衷蜓,對于堆大小而言累提,該次暫停在時(shí)間上是一個(gè)常量。
  4. 在 Android 10 及更高版本中磁浇,CC 會(huì)擴(kuò)展為分代 GC斋陪。它支持輕松回收存留期較短的對象,這類對象通常很快便會(huì)無法訪問置吓。這有助于提高 GC 吞吐量无虚,并顯著延遲執(zhí)行全堆 GC 的需要。

這里有提到

使用 SIGQUIT 獲取 GC 性能信息

如需獲得應(yīng)用的 GC 性能時(shí)序衍锚,請將 SIGQUIT 發(fā)送到已在運(yùn)行的應(yīng)用友题,或者在啟動(dòng)命令行程序時(shí)將 -XX:DumpGCPerformanceOnShutdown 傳遞給 dalvikvm。當(dāng)應(yīng)用獲得 ANR 請求信號(hào) (SIGQUIT) 時(shí)戴质,會(huì)轉(zhuǎn)儲(chǔ)與其鎖定度宦、線程堆棧和 GC 性能相關(guān)的信息告匠。
如需獲得 GC 時(shí)序轉(zhuǎn)儲(chǔ),請使用以下命令:
adb shell kill -S QUIT PID
這會(huì)在 /data/anr/ 中創(chuàng)建一個(gè)文件(名稱中會(huì)包含日期和時(shí)間后专,例如 anr_2020-07-13-19-23-39-817)。此文件包含一些 ANR 轉(zhuǎn)儲(chǔ)信息以及 GC 時(shí)序漾稀。您可以通過搜索“Dumping cumulative Gc timings”(轉(zhuǎn)儲(chǔ)累計(jì) GC 時(shí)序)來確定 GC 時(shí)序。這些時(shí)序會(huì)顯示一些需要關(guān)注的內(nèi)容崭捍,包括每個(gè) GC 類型的階段和暫停時(shí)間的直方圖信息啰脚。暫停信息通常比較重要实夹。
例如(本示例中顯示平均暫停時(shí)間為 1.83 毫秒粒梦,該值應(yīng)該足夠低,在大多數(shù)應(yīng)用中不會(huì)導(dǎo)致丟幀):
young concurrent copying paused: Sum: 5.491ms 99% C.I. 1.464ms-2.133ms Avg: 1.830ms Max: 2.133ms
掛起時(shí)間:
suspend all histogram: Sum: 1.513ms 99% C.I. 3us-546.560us Avg: 47.281us Max: 601us
總耗時(shí)和 GC 吞吐量:
Total time spent in GC: 502.251ms
Mean GC size throughput: 92MB/s
Mean GC object throughput: 1.54702e+06 objects/s
所以要查閱的話只要把/data/anr/anr_2020-07-13-19-23-39-81 pull出來就可以匀们。

分析GC正確性問題的工具
造成 ART 內(nèi)部崩潰的原因多種多樣缴淋。讀取或?qū)懭雽ο笞侄螘r(shí)發(fā)生崩潰可能表明堆損壞。如果 GC 在運(yùn)行時(shí)崩潰泄朴,也可能是由堆損壞造成的重抖。造成堆損壞的最常見原因是應(yīng)用代碼不正確。那CheckJNI就是用來調(diào)試的工具之一祖灰。

CheckJNI 是一種添加 JNI 檢查來驗(yàn)證應(yīng)用行為的模式钟沛;出于性能方面的原因,默認(rèn)情況下不啟用此類檢查局扶。此類檢查將捕獲一些可能會(huì)導(dǎo)致堆損壞的錯(cuò)誤恨统,如使用無效/過時(shí)的局部和全局引用。
adb shell setprop dalvik.vm.checkjni true

CheckJNI 的 forcecopy 模式對于檢測超出數(shù)組區(qū)域末端的寫入很有用三妈。啟用后延欠,forcecopy 會(huì)促使數(shù)組訪問 JNI 函數(shù)返回帶有紅色區(qū)域的副本。紅色區(qū)域是返回的指針末端/始端的一個(gè)區(qū)域沈跨,該區(qū)域具有一個(gè)特殊值,該值在數(shù)組釋放時(shí)得到驗(yàn)證兔综。如果紅色區(qū)域中的值與預(yù)期值不匹配饿凛,表明發(fā)生了緩沖區(qū)溢出或欠載。這會(huì)導(dǎo)致 CheckJNI 中止软驰。
adb shell setprop dalvik.vm.jniopts forcecopy

舉例來說涧窒,當(dāng)寫入超出從 GetPrimitiveArrayCritical 獲取的數(shù)組的末端時(shí),這就是 CheckJNI 應(yīng)捕獲的一個(gè)錯(cuò)誤锭亏。此操作可能會(huì)損壞 Java 堆纠吴。如果寫入發(fā)生在 CheckJNI 紅色區(qū)域內(nèi),則在調(diào)用相應(yīng)的 ReleasePrimitiveArrayCritical 時(shí)慧瘤,CheckJNI 會(huì)捕獲該問題戴已。否則,寫入會(huì)損壞 Java 堆中的某個(gè)隨機(jī)對象锅减,并且可能會(huì)導(dǎo)致將來發(fā)生 GC 崩潰糖儡。如果損壞的內(nèi)存是引用字段,則 GC 可能會(huì)捕獲錯(cuò)誤并輸出錯(cuò)誤消息“Tried to mark <ptr> not contained by any spaces”怔匣。

當(dāng) GC 嘗試標(biāo)記一個(gè)對象但無法找到其空間時(shí)握联,就會(huì)發(fā)生此錯(cuò)誤。此檢查失敗后,GC 會(huì)遍歷根金闽,并嘗試查看無效的對象是否為根代芜。結(jié)果共有兩個(gè)選項(xiàng):對象為根或非根。

???♀?不知道你看懂沒组橄。反正我看翻譯是云里霧里玉工。建議你們看英文去遵班。

CheckJNI's forcecopy mode is useful for detecting writes past the end of array regions. When enabled, forcecopy causes the array access JNI functions to return copies with red zones. A red zone is a region at the end/start of the returned pointer that has a special value, which is verified when the array is released. If the values in the red zone don’t match what's expected, a buffer overrun or underrun occurred. This causes CheckJNI to abort.

這意思就是說forcecopy會(huì)標(biāo)記數(shù)組狭郑,如果使用了被標(biāo)記為release的數(shù)組則就會(huì)報(bào)錯(cuò)翰萨。

An example of an error that CheckJNI should catch is writing past the end of an array obtained from GetPrimitiveArrayCritical. This operation can corrupt the Java heap. If the write is within the CheckJNI red zone area, then CheckJNI catches the issue when the corresponding ReleasePrimitiveArrayCritical is called. Otherwise, the write corrupts some random object in the Java heap and can cause a future GC crash. If the corrupted memory is a reference field, then the GC may catch the error and print the error Tried to mark <ptr> not contained by any spaces.

This error occurs when the GC attempts to mark an object that it can’t find a space for. After this check fails, the GC traverses the roots and tries to see if the invalid object is a root. From here, there are two options: The object is a root or a nonroot object.

盡管如此,我依然還是沒有太理解的雳锋。
但是有一點(diǎn)很奇怪玷过,參考JNI tips
https://developer.android.com/training/articles/perf-jni

    jbyte* data = env->GetByteArrayElements(array, NULL);
    if (data != NULL) {
        memcpy(buffer, data, len);
        env->ReleaseByteArrayElements(array, data, JNI_ABORT);
    }

This grabs the array, copies the first len byte elements out of it, and then releases the array. Depending upon the implementation, the Get call will either pin or copy the array contents. The code copies the data (for perhaps a second time), then calls Release; in this case JNI_ABORT ensures there's no chance of a third copy.
One can accomplish the same thing more simply:

env->GetByteArrayRegion(array, 0, len, buffer);

This has several advantages:

  • Requires one JNI call instead of 2, reducing overhead.
  • Doesn't require pinning or extra data copies.
  • Reduces the risk of programmer error — no risk of forgetting + to call Release after something fails.

理論上因?yàn)槲覀兪褂肎etByteArrayRegion方法其實(shí)是不需要ReleaseByteArrayElements的,但是我們?nèi)サ鬜elease方法又會(huì)發(fā)生泄漏真仲。
(這里面要穿插一個(gè)知識(shí)點(diǎn)袒餐,是如果release的最后一位參數(shù)使用了JNI_COMMIT而不是0的話,那之前??的code是會(huì)又memory leak的墓懂。)


image.png

吶捕仔,然后最后終于在這里找到了答案
https://zhuanlan.zhihu.com/p/148158311
作者舉了個(gè)特別棒的int數(shù)組求和的例子

public native int sumArray(int[] array);
extern "C"
JNIEXPORT jint JNICALL
Java_com_xfhy_jnifirst_MainActivity_sumArray(JNIEnv *env, jobject thiz, jintArray array) {
    //數(shù)組求和
    int result = 0;

    //方式1  推薦使用
    jint arr_len = env->GetArrayLength(array);
    //動(dòng)態(tài)申請數(shù)組
    jint *c_array = (jint *) malloc(arr_len * sizeof(jint));
    //初始化數(shù)組元素內(nèi)容為0
    memset(c_array, 0, sizeof(jint) * arr_len);
    //將java數(shù)組的[0-arr_len)位置的元素拷貝到c_array數(shù)組中
    env->GetIntArrayRegion(array, 0, arr_len, c_array);
    for (int i = 0; i < arr_len; ++i) {
        result += c_array[i];
    }
    //動(dòng)態(tài)申請的內(nèi)存 必須釋放
    free(c_array);

    return result;
}

C層拿到j(luò)intArray之后首先需要獲取它的長度,然后動(dòng)態(tài)申請一個(gè)數(shù)組(因?yàn)镴ava層傳遞過來的數(shù)組長度是不定的,所以這里需要?jiǎng)討B(tài)申請C層數(shù)組),這個(gè)數(shù)組的元素是jint類型的.malloc是一個(gè)經(jīng)常使用的拿來申請一塊連續(xù)內(nèi)存的函數(shù),申請之后的內(nèi)存是需要手動(dòng)調(diào)用free釋放的.然后就是調(diào)用GetIntArrayRegion函數(shù)將Java層數(shù)組拷貝到C層數(shù)組中,然后求和。

對應(yīng)的需要release的:

extern "C"
JNIEXPORT jint JNICALL
Java_com_xfhy_jnifirst_MainActivity_sumArray(JNIEnv *env, jobject thiz, jintArray array) {
    //數(shù)組求和
    int result = 0;

    //方式2  
    //此種方式比較危險(xiǎn),GetIntArrayElements會(huì)直接獲取數(shù)組元素指針,是可以直接對該數(shù)組元素進(jìn)行修改的.
    jint *c_arr = env->GetIntArrayElements(array, NULL);
    if (c_arr == NULL) {
        return 0;
    }
    c_arr[0] = 15;
    jint len = env->GetArrayLength(array);
    for (int i = 0; i < len; ++i) {
        //result += *(c_arr + i); 寫成這種形式,或者下面一行那種都行
        result += c_arr[i];
    }
    //有Get,一般就有Release
    env->ReleaseIntArrayElements(array, c_arr, 0);

    return result;
}

綜上钓葫,就是用free(*ptr)础浮。

{
    // jbyteArray data
    unsigned char *input = new unsigned char[len];
    env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte *>(input));

    ... // actions
    free(input);
    // env->ReleaseByteArrayElements(data, reinterpret_cast<jbyte *>(input), 0);
}

可謂艱苦卓絕地找到了解決方案豆同。
然而其實(shí)這并不是很難的一個(gè)問題對吧影锈。還是對NDK開發(fā)不夠熟悉鸭廷,對debug的方式也不太熟悉。
好在拿到了必現(xiàn)路徑磁滚。
這些年的經(jīng)驗(yàn)只證明了一件事垂攘。
只要問題能給我必現(xiàn)路徑晒他,那么我一定能給你解決方案陨仅。假使不能很快,則只能說還沒太理解触徐。給自己點(diǎn)時(shí)間撞鹉。

對了鸟雏,之前對于越界有提到一個(gè)解決方案是mprotect孝鹊,不過我的嘗試一直以失敗告終惶室。mprotect((inputBytes+allosize-pagesize), pagesize, PROT_READ) 總是返回-1夹界。這讓我百思不得其解可柿。https://cs.android.com/ 源碼看了看也還是沒太get复斥。就當(dāng)成遺留問題先吧目锭。

#include <sys/mman.h>
#include <signal.h>

#include <unistd.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
{
    int pagesize = sysconf(_SC_PAGE_SIZE);
    if (pagesize == -1) {
        LOG("sysconf");
    }
    int allosize = env->GetArrayLength(data);
    if (mprotect((input+allosize-pagesize), pagesize, PROT_READ) == -1) {
        LOG("mprotect");
        return hasObject;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奖唯,隨后出現(xiàn)的幾起案子丰捷,更是在濱河造成了極大的恐慌,老刑警劉巖畅蹂,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件液斜,死亡現(xiàn)場離奇詭異少漆,居然都是意外死亡示损,警方通過查閱死者的電腦和手機(jī)检访,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門脆贵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卖氨,“玉大人筒捺,你說我怎么就攤上這事系吭】铣撸” “怎么了蟆盹?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長败匹。 經(jīng)常有香客問我,道長掀亩,這世上最難降的妖魔是什么槽棍? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任炼七,我火速辦了婚禮豌拙,結(jié)果婚禮上按傅,老公的妹妹穿的比我還像新娘。我一直安慰自己拼岳,他們只是感情好裂问,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布堪簿。 她就那樣靜靜地躺著椭更,像睡著了一般虑瀑。 火紅的嫁衣襯著肌膚如雪滴须。 梳的紋絲不亂的頭發(fā)上扔水,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天主届,我揣著相機(jī)與錄音,去河邊找鬼君丁。 笑死绘闷,一個(gè)胖子當(dāng)著我的面吹牛印蔗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扼倘,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颜曾!你這毒婦竟也來了泛豪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎价卤,沒想到半個(gè)月后慎璧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年阔涉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凶伙,死狀恐怖函荣,靈堂內(nèi)的尸體忽然破棺而出傻挂,到底是詐尸還是另有隱情金拒,我是刑警寧澤套腹,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布幢码,位于F島的核電站症副,受9級(jí)特大地震影響贞铣,放射性物質(zhì)發(fā)生泄漏咕娄。R本人自食惡果不足惜珊擂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一圣贸、第九天 我趴在偏房一處隱蔽的房頂上張望吁峻。 院中可真熱鬧用含,春花似錦啄骇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芽唇,卻和暖如春顾画,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匆笤。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工亲雪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疚膊。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓义辕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寓盗。 傳聞我的和親對象是個(gè)殘疾皇子灌砖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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