最近看 Linux 内核,看到一个问题: malloc 申请的内存,指针为 prt, free 之后如果没有赋值 prt=NULL 会如何? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wind3110991
V2EX    C

最近看 Linux 内核,看到一个问题: malloc 申请的内存,指针为 prt, free 之后如果没有赋值 prt=NULL 会如何?

  •  
  •   wind3110991 2015-04-05 02:28:16 +08:00 2279 次点击
    这是一个创建于 3917 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如:
    在堆段中手动malloc申请一段内存:
    char* ptr = (char*)malloc(10);
    free(ptr);
    //ptr = NULL;假设这步忘记做了

    那么这个ptr指针是不是依然指向那一块内存?
    也就是说我接下来下次依然可以使用ptr指针?
    貌似free的内存块是要够一页大小才会置换页面的
    请问这个ptr如果没有赋值NULL会有什么后果?

    另外,那么问题又来了
    如果我双重释放ptr又会如何?
    free(ptr);
    free(ptr);

    21 条回复    2015-05-30 17:01:11 +08:00
    ryd994
        1
    ryd994  
       2015-04-05 03:05:24 +08:00   1
    依然指向
    用的话可能segfault
    重复free的话会segfault
    赋值null就是为了避免重复free
    free NULL是安全的
    ncisoft
        2
    ncisoft  
       2015-04-05 03:17:11 +08:00 via iPad
    有这闲功夫发帖,都够写段代码测试下了,差评
    RobberPhex
        3
    RobberPhex  
       2015-04-05 11:17:17 +08:00   1
    glibc是不允许多次free的,会出现异常:`Error in './a.out': double free or corruption`

    另外,free小块内存后是可以访问的,因为那块内存还是被glibc管理的,不过这会破坏glibc的内存管理机制。

    不过,释放大块内存的时候,glibc会将其归还给操作系统,此时访问会导致段错误。
    //我猜测:mmap分配的内存,释放时会直接归还操作系统;brk/sbrk在顶端释放大量内存时会归还。
    wind3110991
        4
    wind3110991  
    OP
       2015-04-05 12:21:34 +08:00
    @ncisoft 谢谢
    wind3110991
        5
    wind3110991  
    OP
       2015-04-05 12:30:57 +08:00
    @RobberPhex 就是说free的对象要看是大还是小吧?谢谢你!你解答了我之前的一个问题,就是free之后的内存会不会马上归还给os
    phoeagon
        6
    phoeagon  
       2015-04-05 12:35:48 +08:00 via Android
    @wind3110991 还不还是implementation specific,不是标准定的,不要依赖编译器这种随时能改的实现
    wind3110991
        7
    wind3110991  
    OP
       2015-04-05 16:06:25 +08:00
    @phoeagon = =不太理解,就是说还是要以内核工作机制为准吗
    msg7086
        8
    msg7086  
       2015-04-05 16:36:16 +08:00   2
    @wind3110991 就是说,一旦free了,这块内存就不属于你了。
    接下来的访问就相当于偷着用,抓到就segfault,没抓到就是凑巧。
    就像你租房期满,钥匙还给了房东。
    接下来你再拿偷配的钥匙访问房子就可能会被抓。
    gamexg
        9
    gamexg  
       2015-04-05 22:11:12 +08:00
    还有可能破化程序的其他部分。

    你已经 free 了,其他代码 malloc 时有可能分配到相同位置,然后保存数据。
    jedihy
        10
    jedihy  
       2015-04-05 23:15:03 +08:00 via iPhone
    因为后面用这个变量了吧,节省一条指令
    wind3110991
        11
    wind3110991  
    OP
       2015-04-07 00:30:05 +08:00
    @gamexg 谢啦~~我明白啦
    khan
        12
    khan  
       2015-04-30 10:43:43 +08:00
    因为有很多地方都是这样判断

    if (ptr == NULL) {
    ...do something
    }

    你如果不置空, 后面打算怎么复用.


    free(ptr);
    ptr = NULL; //如果不打算复用指针, 这行代码意义不大. 也没有危险或潜在威胁

    所以这种代码 称之为防御性代码.
    khan
        13
    khan  
       2015-04-30 10:49:50 +08:00
    @RobberPhex: 你说的内容有俩疑点
    1. c++ 中我知道有new alloc 内存复用机制, 可以由 stdlib 来管理代码分配的内存.
    但是 c 中的 alloc 就真的是直接调用系统的内存管理模块了. 应该不存在你说的 libc 管理内存的可能性.

    2. mmap 是内存镜像文件. 我记得没错的话是处理超大型文件时不载入内存的一种实现方式. 直接用磁盘I/O来进行文件操作. 大文件载入内存导致爆内存的问题. 所以 mmap 本身应该可以认为是不占用内存的.

    错漏之处还望斧正.
    RobberPhex
        14
    RobberPhex  
       2015-04-30 12:36:05 +08:00   1
    @khan malloc是libc提供的,在glibc的实现中,是有glibc自己的内存池的。另外,alloc应该也是libc提供的功能,但是linux没有这个内存调用;只有brk调用。

    至于mmap,glibc在分配大块内存时也会用到,在逻辑上占用了内存,但是实际上在读写后,发生缺页中断后才会真正分配。
    khan
        15
    khan  
       2015-04-30 13:58:24 +08:00
    @ryd994 这种情况其实称之为野指针. 情况不可预估. 可能你会发现某个堆的数据突然变化了. 从而导致各种灵异现象.
    另外如果 = NULL, 是空指针, 和内核地址重叠. 如果强制访问. 持有进程会被内核杀死.
    ryd994
        16
    ryd994  
       2015-04-30 14:05:32 +08:00   1
    @khan 所以我说可能Segfault。主要看这个地址是否还属于这个进程。
    访问空指针当然是要死,但是free是可以的。
    khan
        17
    khan  
       2015-04-30 15:00:16 +08:00
    @ryd994 32bit 保护地址模式早就没有远程指针的概念了. 无法访问不属于本进程的地址吧
    ryd994
        18
    ryd994  
       2015-04-30 15:04:38 +08:00   2
    @khan 是的
    所以如果运气好,尽管调用了系统调用,申请释放,但系统还没有释放(有性能因素不是立刻释放),那么地址还属于这个进程,则会出现访问混乱。
    如果操作系统已经释放了内存,就会segfault
    khan
        19
    khan  
       2015-04-30 15:09:44 +08:00
    @ryd994 在@RobberPhex的提示下, 正在看Ptmalloc2的 Free 部分实现. 证实了你的说法.
    qiuyi116
        20
    qiuyi116  
       2015-05-27 22:55:42 +08:00
    free但是不给赋NULL就是自己挖坑,,亲测啊。。因为free知识把ptr指向的内存资源释放归还给了OS,但是呢,ptr还是指向这个虚拟地址的啊。访问ptr的值就会Segmentfault.....
    wind3110991
        21
    wind3110991  
    OP
       2015-05-30 17:01:11 +08:00
    嗯嗯,我也测试过,如果没有赋值ptr = NULL
    之后还是会保留ptr指向的虚拟地址
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1018 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 18:27 PVG 02:27 LAX 10:27 JFK 13:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86