在分析dict.c
和dict.h
的代码时候,发现利用指针是否为空来判断函数是否执行成功。而且该指针可能还是一个 野指针
!
废话不多说,下面结合代码来描述说明!Let’s go!
出现野指针的函数是dictGenericDelete
,位于src/dict.c
源文件。
而该函数分别被两个函数调用:
-
dictUnlink
-
dictDelete
其中dictUnlink
是摘除该key对应的entry,不会释放内存空间。函数执行成功后返回的是该entry的内存地址,空间有效。不会产生野指针。
而dictDelete
是会直接释放key所在entry的内存地址空间,这个调用是会产生野指针的。具体请继续看dictGenericDelete
对应的代码摘录:
第一个红框的内容,如果if条件为真,即nofree=0,就会调用dictFreeUnlinkedEntry
释放he指向的节点,函数代码如下:
先是释放key
,然后释放val
。最后把he
指向的entry
也释放掉。
而最后调用的函数zfree
则定义在src/zmalloc.c
。代码如下:
这代码是带条件编译的。从整个代码逻辑来看,参数ptr
指针,即he
指针指向的内存地址虽然删除了,但he
指针变量中的地址值依然是有效的,即ptr
保存的值和he
的值是相等的。在函数执行完以后,he
就变成了野指针!!!
我们都知道野指针访问内存会存在不可预估的后果。一般都尽量小心!
纵观Redis的源代码,虽然逻辑上都是很清晰明了,会产生野指针的地方也只有删除节点的函数调用,而该函数出现的地方,都仅仅是用该野指针的值来判断函数是否执行成功而已。
可为什么要这样设计呢?为什么不直接类似其他函数,通过参数返回指针地址,函数直接返回值C_OK
或C_ERR
。