日期:2014-05-16  浏览次数:20816 次

C语言内存释放后的野指针
直奔主题:
  代码大致逻辑如下:
  1:先是申请了一块内存,给IP_head:
     IP_head=(IP_HEAD *)calloc(1,sizeof(IP_HEAD));

  2:然后把IP_head作为实参传给函数:
     IPv4_dissect(IP_HEAD *ip_head);

  3: 接着在函数里面把IP_head指向的内存释放掉,并让IP_head指向NULL:
    free(IP_head);
    IP_head = NULL;
 
然后我的疑惑就产生在下面:
 在IPv4_dissect函数里面居然还能对参数ip_head操作:
 打印ip_head ->protocol
 居然还有意义,而且是正确的!
 这是为什么呢?

------解决方案--------------------
收回内存了,只要还没被分配或者修改,那他的值还在那。free之后不会把那快地址清0
------解决方案--------------------
此时你再这么搞只能是未定义的行为,程序可能工作,也可能crash
引用:
那要是在free之后这块内存被其他进程申请了,那么ip_head ->protocol 会怎么样呢

------解决方案--------------------
引用:
此时你再这么搞只能是未定义的行为,程序可能工作,也可能crash
引用:
那要是在free之后这块内存被其他进程申请了,那么ip_head ->protocol 会怎么样呢


我觉得不是这样的吧。应该可以正常的使用!因为分配的那块内存free掉了,指针也指向的NULL。其它进程再分配 到这块内存的时候,就相当于给这块内存重新赋值。没有其它的什么影响!
------解决方案--------------------
引用:
收回内存了,只要还没被分配或者修改,那他的值还在那。free之后不会把那快地址清0


正解,+1


引用:
那要是在free之后这块内存被其他进程申请了,那么ip_head ->protocol 会怎么样呢


不会被其他进程申请的,只可能会被该进程的其他线程申请。每个进程的堆空间是独立的。
如果有被其他线程重新申请到这块内存,并有写过,那你这时候 ip_head ->protocol 可能是修改后的值。
另外,C语言是值传递的,IPv4_dissect(IP_HEAD *ip_head) 函数里面的实参是IP_head的拷贝,在该函数内free掉并置为NULL,该函数外,IP_head还是指向分配的内存的地址的。

------解决方案--------------------
应该是吧。指向NULL了。

引用:
引用:此时你再这么搞只能是未定义的行为,程序可能工作,也可能crash
引用:
那要是在free之后这块内存被其他进程申请了,那么ip_head ->protocol 会怎么样呢

我觉得不是这样的吧。应该可以正常的使用!因为分配的那块内存free掉了,指针也指向的NULL。其它进程再分配 到这块内存的时……

------解决方案--------------------
  3: 接着在函数里面把IP_head指向的内存释放掉,并让IP_head指向NULL:

这句话,在函数里把形参置为NULL??  形参的改变并不影响对应的实参

free内存一般情况并未被操作系统回收,只是libc里的内存管理着变为空闲的了,供下次分配用。所以并不会出现访问原来被释放的内存时并没出现SIGSEGV越界。
同时free也不会使内存被清0,因为那样开销太大。
------解决方案--------------------
谁分配内存就由谁释放,尽量不要写这种代码,因为C语言没有规定free后的内存块不允许访问,因为现代操作系统的内存保护多数是页级别的,无法对内存段做保护,尤其是多线程的情况下,这样随意修改内存很可能崩掉。