strtok 的一个可能被忽略的细节
最近帮他们查了一下线上出现了一个神奇的 bug,先加载A库再加载 B 库 和 先加载 B 库再加载 A 库,会有不一致的行为,看起来不一致的行为是环境变量引起的,仔细排查了发现是strtok引起的,运行时会偷偷抹掉原本的字符串,稍微科普一下。
一、问题代码
1 | #include <stdio.h> |
这段代码本意是把 data 按照冒号拆开,分别访问每一项,打印出来,看起来是没什么问题的,但事实并非如此,输出的结果是
1 | path1:path2:path3:path40 |
发现 data 是被修改过的,其中冒号的位置都被替换为 0 了,这个是strtok_r 偷偷干的一件事。所以,将来有人再把data 当做string处理时,就只能读到path1 了。
二、另一个测试样例
1 | int main() { |
1 | path1:path2:path3:path40 |
同样,使用 strtok 也会这样,会把冒号覆盖为0 。
三、一些细节
这时候问题就解决了,库 A 中使用这种方式访问环境变量 PATH,暗中已经将 PATH 改掉了,导致库 B 中访问的 PATH 其实是残缺的环境变量。
Q:为什么环境变量可以被直接写值?
A:在C里,getenv 的声明是 char * getenv(const char *name) ,没有说是const,所以编译是可以通过的;其次,有个 linux 的常识,环境变量默认是存在栈上的,在程序刚运行时的栈上,读写肯定是允许的。
综上,使用strtok 时一定要保证字符串是临时使用的串,使用完就丢弃掉,因为里面内容不可靠了。