V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dingzs3
V2EX  ›  程序员

看看坛友中还有多少是和我一样长年战斗在 C 上的,答对三个就算

  •  
  •   dingzs3 · 2018-09-25 17:36:23 +08:00 · 7041 次点击
    这是一个创建于 855 天前的主题,其中的信息可能已经有所发展或是发生改变。

    #include<stdio.h>

    #include<string.h>

    #include<stdlib.h>

    void main()

    {

        char *p1=(char *)malloc(1024);  //1k
    
        char *p2=(char *)malloc(4096);  //4k
    
        memset(p2,0,4096);
    
        char *p3=(char *)malloc(8192);  //8k
    
        char *p4=(char *)malloc(128*1024*1024); //128k
    
        char *p5=(char *)malloc(115*1024);//115k
    
        printf("p1=%p p2=%p p3=%p p4=%p p5=%p\n",p1,p2,p3,p4,p5);
    
    
        memset(p2,'1',20);
    
        free(p2);
    
        memset(p2,'y',10);
    
        printf("p2=%s\n",p2);
    
        free(p3); //core
    
        free(p5);
    
        free(p1);
    

    }

    输出: p1=0x1c60010 p2=0x1c60420 p3=0x1c61430 p4=0x7ffbabc2b010 p5=0x1c63440

    p2=yyyyyyyyyy?

    Segmentation fault (core dumped)

    1.p2-p2 为啥不是 1024

    2.p4 的地址为啥和其它的不一样

    3.为啥在 free(p2)之后还能读写 p2

    4.为啥 p2 的打印不是 yyyyyyyyyy1111111111

    5.为啥在 free(p3)的时候会 core

    第 1 条附言  ·  2018-09-26 07:19:08 +08:00
    抱歉,这个没有说清环境,是 linux 下 glibc 开发环境
    第 2 条附言  ·  2018-09-26 09:04:24 +08:00
    问题写错了,是 p2-p1
    第 3 条附言  ·  2018-09-26 09:17:55 +08:00
    可能不同的环境结果不一致,也有可能我理解的也不对,
    程序员不怕错,怕的是错了不知道错哪里,也没有人指点出来,
    所以欢迎大家指正。
    我的理解如下:
    1.p2-p1 不为 1024,是有 16 字节用于标记长度等数据。
    2.p4 是 mmap 出来的内存,是在堆和栈之间找的一个地址空间做的映射,而其它小内存段则是直接偏移 data 段的 e_data (记不清是不是这个了)指针得到的,是由某一个宏控制的,坛友已经指出了。
    3.由于防止内存碎片化,好像是满足 128K 才真正的释放,所以即使 p2 做了 free,但是这段内存还是在的,所以是可以访问的
    4.p2 做 free 后,会在内存头部做 free 的链表指向,所以 memset 导致空闲链表内存指向错误,再 free p3 时 core。
    第 4 条附言  ·  2018-09-26 09:28:44 +08:00
    我只是最近找工作,所以想看看做 C 的还多不多,就业环境如何,所以就来论坛灌个水,哈哈哈哈
    第 5 条附言  ·  2018-09-26 18:14:19 +08:00
    结贴:
    提出这个问题本来是闲的蛋疼,为找工作看看大环境如何而已,代码也不严谨,只是根据自己以往的了解来写个代码验证而已,可能都是错误的。坛友们给的回复也让我受益匪浅,对于这套机制理解也更深了,很感谢。
    对于造成的误解,我很抱歉,希望没有造成伤害,或者是影响大家的心情。
    76 条回复    2018-09-27 17:03:51 +08:00
    andrewhxism
        1
    andrewhxism   2018-09-25 17:40:33 +08:00
    这代码写的。。。
    zmj1316
        2
    zmj1316   2018-09-25 18:14:30 +08:00
    考这种未定义行为不应该指定编译器和运行环境么......
    innoink
        3
    innoink   2018-09-25 18:25:45 +08:00   ❤️ 9
    你以为你在问 c 语言,其实你在问 libc 和操作系统
    besto
        4
    besto   2018-09-25 18:25:51 +08:00
    0, void main 这波可以
    1, 买看懂, p2-p2? p2-p1 可能是因为 fence memory
    2,>128K malloc 会调用 mmap, 另外地址样式和编译器 甚至 32bit/64bit 都有关系
    3, 没有说 free 过后就立刻不可用,甚至这是链表操作的一种偷懒形式
    4, 这个其实还取决于编译器, 甚至可能只有 10 个 yy
    5, 其实和 4 有关联,个人猜测是因为 free 之后,会修改一个链表值, free 之后再用 memset 把 p3 的数据破坏了.
    easylee
        5
    easylee   2018-09-25 18:29:22 +08:00 via Android
    手机上代码没有格式化,可阅读性非常差,不如利用一些贴代码网站。
    zmj1316
        6
    zmj1316   2018-09-25 18:33:10 +08:00   ❤️ 1
    根本不是考 C,都是操作系统的东西把。。。

    1. malloc 会额外记录长度什么的数据,肯定不对齐的
    2. 看 MMAP_THRESHOLD,超了就 mmap 去了
    3. 虚拟内存按 page 分配,估计 p2 的那个 page 还在所以没抛异常
    4.5 和操作系统内存分配链表有关,估计是写 p2 的时候把链表写坏了,VS 里面表现不一样,懒得看了
    JeffKing
        7
    JeffKing   2018-09-25 18:40:32 +08:00
    1. p2 为啥不是 1024?
    不知道你在说什么

    2.p4 的地址为啥和其它的不一样
    p4 分配的地址过大,导致系统无法分配一整块内存

    3.为啥在 free(p2)之后还能读写 p2
    free 只是 free 了 p2 指向的 heap 空间,而 p2 本身没有置空,当然可以读写。只不过这时候是越界读写。

    4.为啥 p2 的打印不是 yyyyyyyyyy1111111111
    因为 p2 已结被 free 了,然后越界写入 y 10,当然是 yyyyyyyy

    5.为啥在 free(p3)的时候会 core
    p2 越界读写写到了 p3 的指针头地址,导致 free(p3)出错
    iceheart
        8
    iceheart   2018-09-25 18:43:32 +08:00 via Android
    楼主注释写错了
    innoink
        9
    innoink   2018-09-25 18:44:52 +08:00
    @JeffKing 你这个基本都是错的
    where2go
        10
    where2go   2018-09-25 18:45:33 +08:00
    没有 void main() 这种写法, 后面没看
    zhicheng
        11
    zhicheng   2018-09-25 18:48:32 +08:00 via iPhone
    答案只有一个,未定义行为。
    在未定义的前提下讨论代码行为没有任何意义。
    catror
        12
    catror   2018-09-25 18:50:17 +08:00 via Android   ❤️ 1
    你问的是 ptmalloc(libc 里面的)的分配策略
    fcten
        13
    fcten   2018-09-25 18:50:27 +08:00
    只要我换一个内存分配的实现,你的问题可能都不成立。
    JeffKing
        14
    JeffKing   2018-09-25 18:51:20 +08:00 via iPhone
    @innoink 那麻烦大佬用清晰的解释打醒我(手动微笑)
    GeruzoniAnsasu
        15
    GeruzoniAnsasu   2018-09-25 19:27:09 +08:00   ❤️ 1
    你以为你在问 C
    我以为你在问 CTF 题怎么做
    lance6716
        16
    lance6716   2018-09-25 20:33:32 +08:00
    mark,等答案
    yulon
        17
    yulon   2018-09-25 20:50:48 +08:00
    看见 void main 就不想看了
    huluhulu
        18
    huluhulu   2018-09-25 21:06:06 +08:00 via iPhone
    void main 很正常……
    zwh2698
        19
    zwh2698   2018-09-25 21:07:38 +08:00 via Android
    敢问兄弟写了几年?另外兄弟 c 中可以存任意基本类型的类型是什么?
    zwh2698
        20
    zwh2698   2018-09-25 21:18:54 +08:00 via Android
    还有兄弟你的问题就是问题
    p2pvideo
        21
    p2pvideo   2018-09-25 21:27:13 +08:00
    @dingzs3
    顺便问问:楼主在哪个城市啊?
    WordTian
        22
    WordTian   2018-09-25 22:10:08 +08:00 via Android
    1.分配的空间除了 1024,还有一段存储分配空间元数据的空间
    2.p4 分配的空间太大,不是从快表(?)分配,具体怎么分的忘了,总之和小空间不连在一块的
    3.好像是将 p2 所在块添加到空表,但 p2 的指针还在
    4.p2 用 memset 赋值时给尾部 /0,printf 输出时到 /0 终止
    5.可能是第一次给 p2 赋值的时候,在尾部添加了 /0,覆盖了 p3 块的元数据,导致报错


    不知道我的答案对不对,只是之前了解 linux 堆的时候看了点资料,凭印象来扯淡
    yankebupt
        23
    yankebupt   2018-09-25 22:54:40 +08:00
    关于 3 4 5 题
    看了一个来源 blackhat.com 的<draft>文档可能是关于某种 heap 实现的,里面这么讲的

    首先 1k 以上 128k 以下不属于 fastbin,但也没有用 mmap(应该)
    说法貌似是说 free()了之后内存因为不够对齐,并没有立刻交还给 OS,而是原 userdata 头部部分填上了用于遍历 free 列表的前进后退两个指针,同时后面的部分有可能被清空了。
    这就导致写 yyy 的时候覆盖了指针...同时导致后面的任意 free 失效...

    两点疑问:第一这种 heap 尤其是 free()实现方式会不会很小众...
    第二:理论上不 free p3,free p4 的话会不会有可能不会 core?
    lolcat
        24
    lolcat   2018-09-26 00:42:16 +08:00   ❤️ 1
    0.void main()没错,只不过为了程序规范性和可移植性,c99 建议使用 int main();
    1.p2-p2 等于 0 ;
    2.malloc 时,系统会自动在堆中找一块连续的内存,只要长度够就行,没规定必须紧挨着前面申请的内存空间,而且在申请的空间的前几个字节是有存储数据的,比如存储了这块空间的大小;
    3.free(p2)只是告诉系统 p2 申请的空间可以重新新被申请了,里面的数据没有被清空,但如果继续对 p2 指向的空间进行操作就是操作野指针;
    4.我觉得不是因为 free(p3)时报的段错误,在你打印野指针 p2 时就会报段错误;
    5.长年战斗在 c 上的楼主连这些问题都没弄懂,我现在连工作都找不到,哎,实在是揪心啊。
    lolcat
        25
    lolcat   2018-09-26 00:55:51 +08:00
    试了一下,果然是在 printf 这句出现段错误的,不是在 free(p3)时
    crazyneo
        26
    crazyneo   2018-09-26 06:17:47 +08:00   ❤️ 1
    都是些操作系统和实现库相关的东西。
    1. 这和 malloc 实现有关,tcmalloc jemalloc ptmalloc dlmalloc 实现各有不同,这个问题没意义。
    2. linux 下超过 128m 分配在映射区,这个也和操作系统有关,aix6 上并不存在类似限制,这个问题没意义。
    3. 还是和 malloc/free 实现有关,free 之后并不是马上被回收,以及看编译器参数,比如 clang 带上-address 参数,直接就 coredump 了,这个问题仍然没意义。
    4 和 5 都是针对被释放内存的瞎搞。

    这几个给学生做考试题都非常的不规范,你好歹写个
    ···
    int a[10];
    memset(a, 1, sizeof(a));
    ···
    类似这种
    dingzs3
        27
    dingzs3   2018-09-26 07:20:30 +08:00
    @zmj1316 抱歉忘记写了
    dingzs3
        28
    dingzs3   2018-09-26 07:21:16 +08:00
    @innoink 哥,看来你是明白人,我觉着长期写 c 的人不可能不懂操作系统和用到的库,以及编译器吧
    dingzs3
        29
    dingzs3   2018-09-26 07:22:56 +08:00
    @besto 老哥可以算一个
    dingzs3
        30
    dingzs3   2018-09-26 07:23:43 +08:00
    dingzs3
        31
    dingzs3   2018-09-26 07:24:46 +08:00
    @iceheart 的确是,应该是 128M,或者是代码里面少乘一个 1024
    dingzs3
        32
    dingzs3   2018-09-26 07:25:19 +08:00
    @catror +1
    dingzs3
        33
    dingzs3   2018-09-26 07:25:43 +08:00
    dingzs3
        34
    dingzs3   2018-09-26 07:28:10 +08:00
    @zwh2698 8 年了,我觉得是指针指向的内存,你可以存任意类型,这个内存想用什么类型操作都可以告诉编译器,或者自己直接用指针+加偏移来弄
    dingzs3
        35
    dingzs3   2018-09-26 09:06:07 +08:00
    @p2pvideo 南京啊,正在想办法回成都

    @where2go 这种写法 gcc 也是支持的吧,我这个不需要返回值做判断,所以一个小验证程序没必要这么严谨吧
    dingzs3
        36
    dingzs3   2018-09-26 09:08:11 +08:00
    dingzs3
        37
    dingzs3   2018-09-26 09:09:15 +08:00
    @lolcat 可能我们的环境不一样吧,用的库也不一样,导致结果不一致了
    shilyx
        38
    shilyx   2018-09-26 09:20:52 +08:00
    1.p2-p1 为啥不是 1024
    malloc 分配了只管在大小范围内用,malloc 也是人实现的,不需要保证任何顺序

    2.p4 的地址为啥和其它的不一样
    malloc 在原来的地方分不出来了,或者不愿在老地方分配了导致的;无论分配的大小,都可能出现

    3.为啥在 free(p2)之后还能读写 p2
    malloc 之后保证可以读写,但是 free 或没 malloc 的,不保证读写,也不保证不可读写,可能能读写也可能不能读写,也可能只能读,也可能只能写

    4.为啥 p2 的打印不是 yyyyyyyyyy1111111111
    可能是也可能不是,malloc 本身有一部分私有内容管理分配信息,不知道他会出现在何处; free 了之后甚至整个堆都有可能消失,说不准

    5.为啥在 free(p3)的时候会 core
    p3 core 了说明已被破坏,但是这是说不准的,不是必然被破坏
    dingzs3
        39
    dingzs3   2018-09-26 09:23:09 +08:00
    @yankebupt 是的,不会 core,这个 mmap 的内存应该是直接释放的,不会遍历链表
    zmj1316
        40
    zmj1316   2018-09-26 09:26:38 +08:00
    @dingzs3 #28 MMAP_THRESHOLD 默认应该= 128k 你是对的......

    @lolcat 打印野指针只要没有 invalid page fault,不会崩的,如果 free p4 再打印 p4 一般会崩,
    找不到工作还是搞 C++吧,不用管这些揪心的事情,我其实是 C++选手😀
    dingzs3
        41
    dingzs3   2018-09-26 09:27:26 +08:00
    @JeffKing 写错了是 p2-p1 的结果为啥不是 1024
    这是 glibc 的内存分配机制问题,小内存是调用的 brk 吧,大内存用的是 mmap,brk 直接对应内核做 e_data 的偏移,所以小内存的虚拟地址是 data 段增长的,而大内存的地址则是在堆栈之间获取一个地址用
    此时 p2 的内存对应的物理内存是没有释放的,所以可以读写,且虚拟地址也是在用户空间的。
    dingzs3
        42
    dingzs3   2018-09-26 09:30:29 +08:00
    @zmj1316 哈哈哈,C 和 C++不分家的,面向对象也就是思想和编译器(语法)上的差距
    where2go
        43
    where2go   2018-09-26 10:09:11 +08:00
    @dingzs3
    $ cat >> a.c << "EOF"
    void main(){}
    EOF
    $ gcc -Wall a.c
    a.c:1:6: warning: return type of 'main' is not 'int' [-Wmain]
    void main(){}
    ^~~~
    dingzs3
        44
    dingzs3   2018-09-26 10:18:28 +08:00
    @where2go 好吧,我错了,忽略 warning,的确是不对的
    ioth
        45
    ioth   2018-09-26 10:40:47 +08:00
    c 的技巧似乎在 java 里面没有用了。
    reus
        46
    reus   2018-09-26 11:34:33 +08:00
    全都是未定义行为,有什么好讨论的。
    malloc / free 的行为和内存分配器的实现有关,换一个实现或者换一个版本,可能就不一样了,glibc 就能保证一样?不能,因为没有谁说了保证,那你就不能依赖它,因为它是未定义行为。
    有些 C/C++ 项目不敢升级编译器版本,就是因为太过于依赖这些未定义行为,导致编译器一升级,这些行为就变了,代码就炸了。
    陋习。
    zwh2698
        47
    zwh2698   2018-09-26 13:03:48 +08:00 via Android
    @dingzs3 8 年坚持不错啦,我也是 c++出身,后来更多 hybrid. 其实答案是 unoin, 因为编译器一直有一个思想就是编译时更多的发现问题,指针太暴力。其实这个也是其他语言 var 关键字模拟,当然 c++中的 var 是另一回事了。希望坚持,底层开发来钱慢,难度大,要么灰产/黑,要么坚持系统编程。
    dingzs3
        48
    dingzs3   2018-09-26 14:06:51 +08:00
    @zwh2698 的确是,以前我学习汇编,就干过逆向工程的活,看那些黑产来钱快。
    but0n
        49
    but0n   2018-09-26 14:10:26 +08:00 via iPhone
    @zwh2698 #19 void*?
    zwh2698
        50
    zwh2698   2018-09-26 14:57:52 +08:00
    @but0n unoin
    bluefalconjun
        51
    bluefalconjun   2018-09-26 15:26:25 +08:00
    go 语言了解一下... :)
    不明白这段 code 有什么讨论的意义...
    @crazyneo @shilyx @reus 都说得很好啊...
    BTW, 芯片公司 sdk 开发了解一下, 这么写 code, 自己 debug 的时候 分分钟飞到不知道哪里去了...
    myself659
        52
    myself659   2018-09-26 15:41:02 +08:00
    这级别过了不前前前公司的编程考试
    dingzs3
        53
    dingzs3   2018-09-26 16:52:01 +08:00
    @bluefalconjun
    @myself659 这个不是为了实现什么功能,也不是实际生产环境用的,只是随便写的程序来验证自己对于知识的理解对不对而已啊,可能一般的 C 开发人员不需要理解这些,就比如 go,它就是尽量屏蔽对于底层的了解,性能也不算太低,开发效率很高。但是在有些场景下,比如 DNS 服务器开发(我现在干的),面对的要求是单机几百万 QPS 的并发,那么我们就必须了解自己的代码是怎么运行的,使用的库是如何实现的,操作系统层面是怎么做的,如何让 CPU 更好的并发执行。场景不一样吧。

    但是一旦你理解了这些,那么学其它语言就相当容易了,比如 go,你就能理解它的内存回收机制,他的基本数据类型是如何实现的,它的 goroutine,chan 底层是啥等等。
    zhicheng
        54
    zhicheng   2018-09-26 17:25:27 +08:00 via iPhone
    你的这个代码,不是什么底层,也不是什么知识,更不能在生产环境使用,除了那种要求指出错误的面试题,不应该用在任何地方。C 语言里明确表明了是未定义行为,就不要花时间去研究如果这样做了会是什么样的结果,因为它真的可以是任何行为,C 语言是一个标准并不是一个 C 实现。

    初级工程师总觉得“了解”一点儿别人不知道的很厉害,殊不知这是高级工程师尽量避免的情况。

    未定义行为的代码 == 错的代码
    reus
        55
    reus   2018-09-26 17:27:24 +08:00
    @dingzs3 我不需要了解这些 C 的未定义行为,照样可以理解 go 的 GC 等底层实现。你这些知识,是很易碎的。
    dingzs3
        56
    dingzs3   2018-09-26 17:38:52 +08:00
    @zhicheng
    @reus 我们不是为了争论而争论啊,都说了只是看看有多少是长期做 C 的,这个代码很简单,只是为了看看有哪些人是能够从这个代码看到 glibc 库的内存分配机制,linux 内核的内存分配机制。我知道现在的趋势是尽量多关注业务,而不是陷入底层这个无底洞,所以我上面也是说了,如果像我这样陷进去的还好不好找工作,长期干 C 的还多不多。
    我也没有说必须懂 c 才能懂 go 啊,只是说如果懂 C 的人可能会比不懂的人更好的理解 go 的机制,但也只是可能,并不是绝对的,就好象说已经懂一门语言的人去学习新的语言,总是比一个啥开发语言都不会的人,稍微有点优势而已。
    zhicheng
        57
    zhicheng   2018-09-26 17:51:39 +08:00 via iPhone
    我并没有争论,我只是在说你在误人子弟。
    dingzs3
        58
    dingzs3   2018-09-26 17:58:41 +08:00
    @zhicheng 好吧,我错了,我问个问题已经变成误人子弟了,难道我出个题应该这样说:懂 glibc 和内核原理的人进来,不懂的别看。技术上没有啥不能讨论的啊,了解的可以讨论一下,不了解的可以略过,或者是看着乐呵乐呵。
    zhicheng
        59
    zhicheng   2018-09-26 18:07:28 +08:00 via iPhone
    因为你的代码本来就是错的,你在为错的代码强行找原因,你今天的 glibc 版本是这个行为,下一个可能是另一个行为,甚至不同的编译参数产生的行为也不一样。你要讨论 glibc 和 linux 就直接讨论,出个错的题目要“考”一下别人也是有趣。

    如同法律上写了红灯不要过马路,你非要去讨论什么样的情况下红灯可以过马路,抱歉我理解不了这种行为。
    dingzs3
        60
    dingzs3   2018-09-26 18:11:02 +08:00
    @zhicheng 可能是我表述的有问题吧,我没有考的意思,只是希望讨论一下,这个特意写错的代码只是为了验证库和内核的机制而已,希望拿出来讨论。如果让你这样理解,那我道歉。
    zealot0630
        61
    zealot0630   2018-09-26 20:20:28 +08:00
    1.p2-p2 为啥不是 1024

    glibc 会在 p2 前面用几个字节记录 p2 的分配信息

    2.p4 的地址为啥和其它的不一样

    p4 用 mmap 分配的,小内存用 brk,大内存用 mmap

    3.为啥在 free(p2)之后还能读写 p2

    brk 内存分配了就不能释放

    4.为啥 p2 的打印不是 yyyyyyyyyy1111111111

    p2 还給 glibc 时候,glibc 会吧这段内存返还给链表,p2 这里指向 glibc 内部维护空闲内存的链表

    5.为啥在 free(p3)的时候会 core

    glibc 维护的空闲内存链表被你破坏了,glibc 就崩了
    dingzs3
        62
    dingzs3   2018-09-26 22:10:18 +08:00
    zmj1316
        63
    zmj1316   2018-09-27 07:24:11 +08:00 via Android
    看 lz 被喷这么惨,帮 lz 说句话,了解这些 ub 的结果不是为了去写这些 ub. ,而是为了在各种不可抗性因素之下,比如笔误 或者🐷队友,导致使用了 ub 而出现 bug 能够尽早发现原因 debug,
    假如 崩溃在 free p3 而 free p2 在很前面,起码能考虑到这个可能性,
    而写 go 的可能一般不会遇到这种情况,这也是为什么我喜欢 CPP 多于 C,能少很多糟心的事

    @zhicheng
    @reus
    zhicheng
        64
    zhicheng   2018-09-27 09:46:03 +08:00 via iPhone
    @zmj1316 工作这么多年,头一回听说用 Ub 的行为来 debug,你知道 ub 这是哪两个词的缩写?调试内存问题,你可以用 valgrind 可以用 addresssanitizer,能通过 ub 的行为来定位 bug ?我猜你是神。
    zmj1316
        65
    zmj1316   2018-09-27 10:07:55 +08:00
    @zhicheng 兄弟语文没学好啊...我说的是因为用了 UB 出现 bug,没说用 UB 来 debug 啊......我又不是来抬杠的
    zmj1316
        66
    zmj1316   2018-09-27 10:12:28 +08:00
    @zhicheng 讲的明白一点

    `如同法律上写了红灯不要过马路,你非要去讨论什么样的情况下红灯可以过马路,抱歉我理解不了这种行为。`

    就是为了明白,路上撞死了个人,不一定是汽车司机故意撞死的,也可能是行人自己闯红灯作死的,划分责任的时候,不要全都怪司机,说不定是行人的责任
    dingzs3
        67
    dingzs3   2018-09-27 10:20:47 +08:00
    @zmj1316 哥们,技术上的问题讨论明白就行了,没必要把问题升华讨论更上层的东西,已经结贴了,本来想删除的,但是不知道怎么删除,而且有十几个人收藏了。技术讨论最好永远局限于技术,也多谢你帮忙解释。
    zhicheng
        68
    zhicheng   2018-09-27 10:24:12 +08:00 via iPhone
    @zmj1316 你说的那不是废话吗?用了 UB 基本上都是要出 Bug 的,大部分 Bug 也是由 UB 引起的,是我语文没学好,还是你逻辑没学好?还是知道 UB 会出现 Bug 是件很牛逼的事?
    zmj1316
        69
    zmj1316   2018-09-27 10:36:54 +08:00
    @dingzs3 抱歉,我的锅,工作不饱和,老老实实搬砖去了,C++写久了 OS 层的东西都快忘光了,感谢 LZ 还让我复习一下 hhhhh
    dingzs3
        70
    dingzs3   2018-09-27 10:38:15 +08:00
    @zmj1316 哈哈哈,以后多交流啊,哥们,C++那套我不怎么熟
    bluefalconjun
        71
    bluefalconjun   2018-09-27 13:27:52 +08:00
    @dingzs3 如果是为了了解相关知识, 真的应该看书 看 spec 看操作系统 /编译器的实现代码...
    在这里写这种 code 来了解... 实话说, 做不到的... 就像你写个黑盒的测试代码 想要来理解里面的实现.. 白盒测试都不一定能完成的事情...
    wizardforcel
        72
    wizardforcel   2018-09-27 14:11:19 +08:00 via Android
    wizardforcel
        73
    wizardforcel   2018-09-27 14:14:42 +08:00 via Android
    @zhicheng 首先 glibc 不是一种实现,而是很多种实现,比如 tmalloc。固定了版本号就固定了实现。

    其次,就算你不去利用,黑客也会利用。你觉得被黑是很好玩的事情么??

    你以为标准库和编译器都是严格按照标准实现的??你自己搞搞 plt,做做语言律师也就算了,还把这种陋习搬到实际生产中来。你的心真大。呵呵。
    wizardforcel
        74
    wizardforcel   2018-09-27 14:29:39 +08:00
    @zhicheng

    > 初级工程师总觉得“了解”一点儿别人不知道的很厉害,殊不知这是高级工程师尽量避免的情况。

    我认为正好相反,初级工程师只需要知道那个是 UB,高级工程师需要知道具体实现是怎么回事。

    虽然大家都知道不能用 UB,但是,知道了产生的后果并且知道为什么不能用,更深刻一些。

    知其然而知其所以然,懂??
    zhicheng
        75
    zhicheng   2018-09-27 15:20:12 +08:00 via iPhone
    @wizardforcel 刚好相反,高级工程师根本就不会关心 UB 会产生什么样的行为,因为无论它产生什么样的行为,都是错的,哪怕程序看起来正确。

    你知道 UB 会产生什么样的行为能避免被黑?程序能更安全?不,能让程序更安全的是从一开始就尽量避免引入 UB。

    没有什么实现是完全正确的,但你明显不能往肯定错误的方向走啊。
    aihimmel
        76
    aihimmel   2018-09-27 17:03:51 +08:00
    @GeruzoniAnsasu 真实堆利用题目
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4907 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 01:53 · PVG 09:53 · LAX 17:53 · JFK 20:53
    ♥ Do have faith in what you're doing.