为什么我修改了strerror函数返回的字符串会coredump呢?
#include <stdio.h>#include <errno.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *fp;
fp = fopen("file.txt", "r");
if(fp == NULL) {
char *str = strerror(errno);
*str = '!';
printf("Error: %s\n", strerror(errno));
}
return 0;
}
运行时提示:Segmentation fault (core dumped) The strerror() function returns a pointer to a string that describes the error code passed in the argument errnum, possibly using the LC_MESSAGES part of the current locale to select the appropriate language.(Forexample,iferrnumisEINVAL, the returned description will be "Invalid argument".)This string must not be modified by the application, but may be modified by a subsequent call to strerror() or strerror_l().No other library function, including perror(3), will modify this string.
strerror()函数返回一个指向字符串的指针,该字符串描述在参数errnum中传递的错误代码,可能使用当前语言环境的LC_MESSAGES部分来选择适当的语言。(例如,如果errnum是EINVAL,返回的描述将是“无效参数”。)此字符串不能由应用程序修改,但可以通过后续调用strerror()或strerror_l()进行修改。没有其他标准库函数,包括perror(3),将修改此字符串。 char *str = strerror(errno);
这个函数返回的指针应该指向了函数 strerror(); 中属于局部变量的字符数组变量,当函数退出的时候,这个数组所占用的内存空间已经被系统释放,被用于其它需要,所以, 下一句
*str = '!';
可能写入了一个不允许写入的内存区域,所以,导致奔溃。
jackz007 发表于 2022-10-26 21:41
这个函数返回的指针应该指向了函数 strerror(); 中属于局部变量的字符数组变量,当函数退出的时 ...
返回的这个字符串不可能在局部数组里面
函数返回后这个字符串不可能被释放
要不然调用这个函数的意义何在?
sh-5.1$ cat main.c
#include <stdio.h>
#include <string.h>
const char *get_str(void) {
char buff[] = "hello world!";
const char *p = buff;
return p;
}
void print(const char *str) {
puts(str);
}
int main(void) {
print(strerror(0));
print(get_str());
return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$ ./main
Success
zU
sh-5.1$
本帖最后由 jackz007 于 2022-10-26 22:07 编辑
人造人 发表于 2022-10-26 21:57
返回的这个字符串不可能在局部数组里面
函数返回后这个字符串不可能被释放
要不然调用这个函数的意义何 ...
我以为是他自己写的函数,我看因为没有传递字符数组进去,返回的字符串的根就应该是在函数内部。
如果这样说就对了,返回的是常量字符串,而常量字符串在程序内是绝对不可以修改的,如果修改,就会奔溃,以前有个鱼油要求通过调用一个无参函数,修改 main() 中一个字符串的时候就试过,那个就是一个常量字符串,根本不可能修改。 本帖最后由 人造人 于 2022-10-26 22:15 编辑
可以想到,strerror这个函数就是返回了一个字符串常量
这个常量存储在只读存储区
如果操作系统支持的话,对只读存储区的写操作会被捕获到,而系统的默认处理程序会选择杀死这个进程
#include <stdio.h>
#include <string.h>
char *get_str(void) {
return "hello world!";
}
void print(const char *str) {
puts(str);
}
int main(void) {
char *str = get_str();
puts(str);
*str = '0';
return 0;
}
sh-5.1$ readelf -S main
There are 37 section headers, starting at offset 0x4a48:
Section Headers:
Name Type Address Offset
Size EntSize FlagsLinkInfoAlign
[ 0] NULL 000000000000000000000000
00000000000000000000000000000000 0 0 0
[ 1] .interp PROGBITS 000000000000031800000318
000000000000001c0000000000000000 A 0 0 1
。。。
.rodata PROGBITS 000000000000200000002000
00000000000000110000000000000000 A 0 0 4
.eh_frame_hdr PROGBITS 000000000000201400002014
00000000000000340000000000000000 A 0 0 4
。。。
00000000000001f20000000000000000 0 0 1
.shstrtab STRTAB 0000000000000000000048d2
00000000000001760000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
sh-5.1$
sh-5.1$ xxd main
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000.ELF............
00000010: 0300 3e00 0100 0000 4010 0000 0000 0000..>.....@.......
00000020: 4000 0000 0000 0000 484a 0000 0000 0000@.......HJ......
。。。
00001ff0: 0000 0000 0000 0000 0000 0000 0000 0000................
00002000: 0100 0200 6865 6c6c 6f20 776f 726c 6421....hello world!
00002010: 0000 0000 011b 033b 3000 0000 0500 0000.......;0.......
00002020: 0cf0 ffff 6400 0000 2cf0 ffff 4c00 0000....d...,...L...
。。。
00005360: d248 0000 0000 0000 7601 0000 0000 0000.H......v.......
00005370: 0000 0000 0000 0000 0100 0000 0000 0000................
00005380: 0000 0000 0000 0000 ........
sh-5.1$
jackz007 发表于 2022-10-26 22:06
我以为是他自己写的函数,我看因为没有传递字符数组进去,返回的字符串的根就应该是在函数内部 ...
是的
如果编译器支持的话,会把字符串常量放在只读存储区
如果操作系统支持的话,对只读存储区的写操作会被捕获到,而系统的默认处理程序会选择杀死这个进程
人造人 发表于 2022-10-26 22:11
可以想到,strerror这个函数就是返回了一个字符串常量
这个常量存储在只读存储区
如果操作系统支持的话, ...
可以看到,"hello world!" 这个字符串就存放在 .rodata 段
人造人 发表于 2022-10-26 22:18
可以看到,"hello world!" 这个字符串就存放在 .rodata 段
ok 本帖最后由 桃花飞舞 于 2022-10-26 23:29 编辑
虽然能看懂答案,却没看懂问题,从楼上的答案隐约感觉是这句导致的错误*str = '!'; core dumped通常在linux的内核中会出现
页:
[1]