NSObject

NSObject

Review

Screen Shot 2019-12-19 at 9.04.57 PM.png

toggle the button to check the whole call heap stack.

When run the code ABCRobot *r = [ABCRobot alloc]; You will find before it calls the

// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

It call the method below instead:

// Calls [cls alloc].
id
objc_alloc(Class cls)
{
    return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}

then it will come to here:

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (slowpath(checkNil && !cls)) return nil;

#if __OBJC2__
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        // No alloc/allocWithZone implementation. Go straight to the allocator.
        // fixme store hasCustomAWZ in the non-meta class and 
        // add it to canAllocFast's summary
        if (fastpath(cls->canAllocFast())) {
            // No ctors, raw isa, etc. Go straight to the metal.
            bool dtor = cls->hasCxxDtor();
            id obj = (id)calloc(1, cls->bits.fastInstanceSize());
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            obj->initInstanceIsa(cls, dtor);
            return obj;
        }
        else {
            // Has ctor or raw isa or something. Use the slower path.
            id obj = class_createInstance(cls, 0);
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            return obj;
        }
    }
#endif

    // No shortcuts available.
    if (allocWithZone) return [cls allocWithZone:nil];
    return [cls alloc];
}

then it calls [cls alloc] which is the code below:

 (id)alloc {
    return _objc_rootAlloc(self);
}

// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

Guess before we call the method, the system bind the symbol table. When initialize macho, bind the symbol (alloc - objc_alloc) , only once.

in objc-runtime-new.mm, check the code in line 13:

/***********************************************************************
* fixupMessageRef
* Repairs an old vtable dispatch call site. 
* vtable dispatch itself is not supported.
**********************************************************************/
static void 
fixupMessageRef(message_ref_t *msg)
{    
    msg->sel = sel_registerName((const char *)msg->sel);

    if (msg->imp == &objc_msgSend_fixup) { 
        if (msg->sel == SEL_alloc) {
            msg->imp = (IMP)&objc_alloc;
        } else if (msg->sel == SEL_allocWithZone) {
            msg->imp = (IMP)&objc_allocWithZone;
        } else if (msg->sel == SEL_retain) {
            msg->imp = (IMP)&objc_retain;
        } else if (msg->sel == SEL_release) {
            msg->imp = (IMP)&objc_release;
        } else if (msg->sel == SEL_autorelease) {
            msg->imp = (IMP)&objc_autorelease;
        } else {
            msg->imp = &objc_msgSend_fixedup;
        }
    } 
    else if (msg->imp == &objc_msgSendSuper2_fixup) { 
        msg->imp = &objc_msgSendSuper2_fixedup;
    } 
    else if (msg->imp == &objc_msgSend_stret_fixup) { 
        msg->imp = &objc_msgSend_stret_fixedup;
    } 
    else if (msg->imp == &objc_msgSendSuper2_stret_fixup) { 
        msg->imp = &objc_msgSendSuper2_stret_fixedup;
    } 
#if defined(__i386__)  ||  defined(__x86_64__)
    else if (msg->imp == &objc_msgSend_fpret_fixup) { 
        msg->imp = &objc_msgSend_fpret_fixedup;
    } 
#endif
#if defined(__x86_64__)
    else if (msg->imp == &objc_msgSend_fp2ret_fixup) { 
        msg->imp = &objc_msgSend_fp2ret_fixedup;
    } 
#endif
}

this method can be found called in _read_images.

#if SUPPORT_FIXUP
    // Fix up old objc_msgSend_fixup call sites
    for (EACH_HEADER) {
        message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
        if (count == 0) continue;

        if (PrintVtables) {
            _objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
                         "call sites in %s", count, hi->fname());
        }
        for (i = 0; i < count; i++) {
            fixupMessageRef(refs+i);
        }
    }

    ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
#endif

looks like it is fix up.

Compare with these two methods:

// Calls [cls alloc].
id
objc_alloc(Class cls)
{
    return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}

// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

both of them call the callAlloc method, but different parameters for zone .

isa connect the object and class

let's check the code:

        LGPerson *object = [LGPerson alloc];
        NSLog(@"Hello, World! %@",object);

break point at line 2, then:

(lldb) x/4xg object
0x101824790: 0x001d8001000014b9 0x0000000000000000
0x1018247a0: 0x0000000000000002 0x00007fff99649588

So how to improve the first place is isa ?

let's try:

(lldb) p/t 0x001d8001000014b9
(long) $1 = 0b0000000000011101100000000000000100000000000000000001010010111001

p/t 0x.... // make 16 to 2

p/o ... // make 16 to 8

p/d ... // make 16 to 10

let's see the class:

(lldb) p/x LGPerson.class
(Class) $2 = 0x00000001000014b8 LGPerson

Then:

(lldb) p/t (uintptr_t)LGPerson.class
(uintptr_t) $3 = 0b0000000000000000000000000000000100000000000000000001010010111000

Then check the isa :

(lldb) p/t $1>>3
(long) $8 = 0b0000000000000011101100000000000000100000000000000000001010010111
(lldb) p/t $8<<3
(long) $9 = 0b0000000000011101100000000000000100000000000000000001010010111000
(lldb) p/t $9<<17
(long) $10 = 0b0000000000000010000000000000000000101001011100000000000000000000
(lldb) p/t $10>>17
(long) $11 = 0b0000000000000000000000000000000100000000000000000001010010111000

$3 = 0b0000000000000000000000000000000100000000000000000001010010111000

$11 = 0b0000000000000000000000000000000100000000000000000001010010111000

They are the same. So we can iimprove that the first place is isa

This way is a little bit hard, let's try another one:

(lldb) x/4xg object
0x101824790: 0x001d8001000014b9 0x0000000000000000
0x1018247a0: 0x0000000000000002 0x00007fff99649588

we can use :

object_getClass(object);

Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

inline Class 
objc_object::getIsa() 
{
    if (!isTaggedPointer()) return ISA();

    uintptr_t ptr = (uintptr_t)this;
    if (isExtTaggedPointer()) {
        uintptr_t slot = 
            (ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
        return objc_tag_ext_classes[slot];
    } else {
        uintptr_t slot = 
            (ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
        return objc_tag_classes[slot];
    }
}

inline Class 
objc_object::ISA() 
{
    assert(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

#   define ISA_MASK        0x00007ffffffffff8ULL

Got the ISA_MASK!!

(lldb) x/4xg object
0x101824790: 0x001d8001000014b9 0x0000000000000000
0x1018247a0: 0x0000000000000002 0x00007fff99649588
(lldb) p/x LGPerson.class
(Class) $13 = 0x00000001000014b8 LGPerson
(lldb) p/x 0x001d8001000014b9 & 0x00007ffffffffff8
(long) $14 = 0x00000001000014b8
(lldb) po 0x00000001000014b8
LGPerson

$13 == $14 !!!!

analysis isa

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

ISA_MASK has different value in different architecture.

Q2: We can create seveal objects, how about class?

class has only one.

//MARK: - 分析类对象内存存在个数
void lgTestClassNum(){
    Class class1 = [LGPerson class];
    Class class2 = [LGPerson alloc].class;
    Class class3 = object_getClass([LGPerson alloc]);
    Class class4 = [LGPerson alloc].class;
    NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        LGPerson *p = [LGPerson alloc];
        NSLog(@"%@",p);
        lgTestClassNum();
        NSLog(@"isa 我来了!");
    }
    return 0;
}

Result:

2019-12-19 22:21:18.856127+0800 001-对象isa[1969:194885] <LGPerson: 0x1006ba910>
2019-12-19 22:21:18.856628+0800 001-对象isa[1969:194885] 
0x100003108-
0x100003108-
0x100003108-
0x100003108
2019-12-19 22:21:18.856730+0800 001-对象isa[1969:194885] isa 我来了!

We proved the class has only one in memory.

Let's see the memory structure of the class:

(lldb) x/4xg LGPerson.class
0x1000014c0: 0x001d800100001499 0x0000000100b38140
0x1000014d0: 0x00000001003db240 0x0000000000000000
(lldb) po 0x1000014c0
LGPerson

So the first pointer of the class is point to itself?

Actually, it's meta class. So let's prove that the isa of class is point to tht meta class.

(lldb) p/x 0x001d800100001499 & 0x00007ffffffffff8
(long) $2 = 0x0000000100001498
(lldb) po 0x0000000100001498
LGPerson

(lldb) x/4xg 0x0000000100001498
0x100001498: 0x001d800100b380f1 0x0000000100b380f0
0x1000014a8: 0x0000000100f755a0 0x0000000100000007
(lldb) p/x 0x001d800100b380f1 & 0x00007ffffffffff8
(long) $4 = 0x0000000100b380f0
(lldb) po 0x0000000100b380f0
NSObject

(lldb) p/x NSObject.class
(Class) $6 = 0x0000000100b38140 NSObject
(lldb) x/4xg NSObject.class
0x100b38140: 0x001d800100b380f1 0x0000000000000000
0x100b38150: 0x0000000101f09db0 0x0000000200000003
(lldb) p/x 0x001d800100b380f1 & 0x00007ffffffffff8
(long) $8 = 0x0000000100b380f0
(lldb) po 0x0000000100b380f0
NSObject

we have found:

SubInstance -> subclass -> meta Class -> root meta Class -> root meta Class(itself)

NSObject Instance -> root NSObject Class -> root meta Class

(lldb) x/4xg 0x0000000100b380f0 // (root meta class)
0x100b380f0: 0x001d800100b380f1 0x0000000100b38140
0x100b38100: 0x0000000102d696e0 0x0000000500000007
(lldb) p/x 0x0000000100b380f0 & 0x00007ffffffffff8
(long) $10 = 0x0000000100b380f0
(lldb) po 0x0000000100b380f0
NSObject

we can also prove in this way:

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        LGPerson *p = [LGPerson alloc];
        NSLog(@"%@",p);
        lgTestNSObject();
//        lgTypes();
        NSLog(@"isa 我来了!");
    }
    return 0;
}

void lgTestNSObject(){
    // NSObject实例对象
    NSObject *object1 = [NSObject alloc];
    // NSObject类
    Class class = object_getClass(object1);
    // NSObject元类
    Class metaClass = object_getClass(class);
    // NSObject根元类
    Class rootMetaClass = object_getClass(metaClass);
    // NSObject根根元类
    Class rootRootMetaClass = object_getClass(rootMetaClass);
    NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",object1,class,metaClass,rootMetaClass,rootRootMetaClass);
}

result is:

2019-12-19 22:46:18.845295+0800 001-对象isa[2008:209154] 
0x1005a2500 实例对象
0x7fff9b38a118 类
0x7fff9b38a0f0 元类
0x7fff9b38a0f0 根元类
0x7fff9b38a0f0 根根元类
2019-12-19 22:46:18.845361+0800 001-对象isa[2008:209154] isa 我来了!
isa流程图.png
  • root class 's superclass is NSObject class
  • NSObject's superclass is nil

Class's struct

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
....

}

we find the 1st variable is ISA, the 2nd is superclass.

So we can prove the root class's super class

(lldb) x/4xg NSObject.class
[0x100b38140]: 0x001d800100b380f1 0x0000000000000000
0x100b38150: 0x0000000101e13810 0x0000000200000003
(lldb) p/x 0x001d800100b380f1 & 0x00007ffffffffff8
(long) $1 = 0x0000000100b380f0
(lldb) po 0x0000000100b380f0
NSObject

(lldb) x/4xg 0x0000000100b380f0
0x100b380f0: 0x001d800100b380f1 [0x0000000100b38140]
0x100b38100: 0x0000000100f5a6d0 0x0000000400000007
(lldb) po 0x0000000100b38140
NSObject

Object

@interface LGPerson : NSObject
  
@end

@implementation LGPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"123");
    }
    return 0;
}

Clang -rewrite-objc main.m -o main.cpp

#ifndef _REWRITER_typedef_LGPerson
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
};

struct NSObject_IMPL {
    Class isa;
};

we find object is the struct and inherit the property from the super class. What about the property in itself?

// 对象 -编译 --> 结构体 父类的属性继承过来
// 下节课开始 - 展开分析 类的结构 (对象 - isa)
// 细节分析 -

@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *name; // 属性的区别
@end

@implementation LGPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"123");
    }
    return 0;
}
#ifndef _REWRITER_typedef_LGPerson
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

extern "C" unsigned long OBJC_IVAR_$_LGPerson$_name;
struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_name;
};

// @property (nonatomic, copy) NSString *name;
/* @end */


// @implementation LGPerson


static NSString * _I_LGPerson_name(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_LGPerson_setName_(LGPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _name), (id)name, 0, 1); }
// @end

...
  
static struct /*_method_list_t*/ {
unsigned int entsize;  // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[2];
} _OBJC_$_INSTANCE_METHODS_LGPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
2,
  // @ return value
  // @ -> id 0 - 7
  // : -> sel 8 - 15
{{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LGPerson_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LGPerson_setName_}}
};

check code here:

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        LGPerson *p = [LGPerson alloc];
        NSLog(@"%@",p);
        lgTypes();
        NSLog(@"isa 我来了!");
    }
    return 0;
}

void lgTypes(){
    NSLog(@"char --> %s",@encode(char));
    NSLog(@"int --> %s",@encode(int));
    NSLog(@"short --> %s",@encode(short));
    NSLog(@"long --> %s",@encode(long));
    NSLog(@"long long --> %s",@encode(long long));
    NSLog(@"unsigned char --> %s",@encode(unsigned char));
    NSLog(@"unsigned int --> %s",@encode(unsigned int));
    NSLog(@"unsigned short --> %s",@encode(unsigned short));
    NSLog(@"unsigned long --> %s",@encode(unsigned long long));
    NSLog(@"float --> %s",@encode(float));
    NSLog(@"bool --> %s",@encode(bool));
    NSLog(@"void --> %s",@encode(void));
    NSLog(@"char * --> %s",@encode(char *));
    NSLog(@"id --> %s",@encode(id));
    NSLog(@"Class --> %s",@encode(Class));
    NSLog(@"SEL --> %s",@encode(SEL));
    int array[] = {1,2,3};
    NSLog(@"int[] --> %s",@encode(typeof(array)));
    typedef struct person{
        char *name;
        int age;
    }Person;
    NSLog(@"struct --> %s",@encode(Person));
    
    typedef union union_type{
        char *name;
        int a;
    }Union;
    NSLog(@"union --> %s",@encode(Union));

    int a = 2;
    int *b = {&a};
    NSLog(@"int[] --> %s",@encode(typeof(b)));
}

Result:

2019-12-19 23:19:32.412972+0800 001-对象isa[2099:227343] <LGPerson: 0x1007100b0>
2019-12-19 23:19:32.413433+0800 001-对象isa[2099:227343] char --> c
2019-12-19 23:19:32.413491+0800 001-对象isa[2099:227343] int --> i
2019-12-19 23:19:32.413534+0800 001-对象isa[2099:227343] short --> s
2019-12-19 23:19:32.413573+0800 001-对象isa[2099:227343] long --> q
2019-12-19 23:19:32.413641+0800 001-对象isa[2099:227343] long long --> q
2019-12-19 23:19:32.413692+0800 001-对象isa[2099:227343] unsigned char --> C
2019-12-19 23:19:32.413738+0800 001-对象isa[2099:227343] unsigned int --> I
2019-12-19 23:19:32.413782+0800 001-对象isa[2099:227343] unsigned short --> S
2019-12-19 23:19:32.413825+0800 001-对象isa[2099:227343] unsigned long --> Q
2019-12-19 23:19:32.413867+0800 001-对象isa[2099:227343] float --> f
2019-12-19 23:19:32.413909+0800 001-对象isa[2099:227343] bool --> B
2019-12-19 23:19:32.413953+0800 001-对象isa[2099:227343] void --> v
2019-12-19 23:19:32.413995+0800 001-对象isa[2099:227343] char * --> *
2019-12-19 23:19:32.414036+0800 001-对象isa[2099:227343] id --> @
2019-12-19 23:19:32.414080+0800 001-对象isa[2099:227343] Class --> #
2019-12-19 23:19:32.414122+0800 001-对象isa[2099:227343] SEL --> :
2019-12-19 23:19:32.414171+0800 001-对象isa[2099:227343] int[] --> [3i]
2019-12-19 23:19:32.414654+0800 001-对象isa[2099:227343] struct --> {person=*i}
2019-12-19 23:19:32.414687+0800 001-对象isa[2099:227343] union --> (union_type=*i)
2019-12-19 23:19:32.414712+0800 001-对象isa[2099:227343] int[] --> ^i
2019-12-19 23:19:32.414764+0800 001-对象isa[2099:227343] isa 我来了!

reference

Screen Shot 2019-12-19 at 11.23.52 PM.png

clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m

xcrun -sdk iphonesimulator clang -rewrite-objc ViewController.m

xcrun -sdk iphoneos clang -rewrite-objc ViewController.m

// 对象 -编译 --> 结构体 父类的属性继承过来

@interface LGPerson : NSObject{
    NSString *name; // 成员变量 : 底层编译不会生成相应的 setter getter
    // lgTeacher *t;    // 实例变量 : 是一种特殊的成员变量 (类声明而来 实例 - id (void *))
}
@property (nonatomic, copy) NSString *name; // 属性的区别
@end

@implementation LGPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"123");
    }
    return 0;
}

The difference between member variable and property:

#ifndef _REWRITER_typedef_LGPerson
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

extern "C" unsigned long OBJC_IVAR_$_LGPerson$_name;
struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *name;
    NSString *_name;
};

// @property (nonatomic, copy) NSString *name;
/* @end */


// @implementation LGPerson


static NSString * _I_LGPerson_name(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_LGPerson_setName_(LGPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _name), (id)name, 0, 1); }
// @end

Q&A

NSProxy class's isa is not point to NSObject. It point to NSProxy meta class. And NSProxy meta class's isa point to itself. Also NSProxy's super class is not NSObject, it's nil.

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

推荐阅读更多精彩内容