[英]Segmentation fault using snprintf
我在使用snprintf時遇到了奇怪的細分錯誤。
這是我的代碼:
size_t tmp_size = win_data_width; // win_data_width is the width of a Ncurses window
char *tmp = new(tmp_size); // <------- new == malloc MACRO
snprintf(tmp,
tmp_size,
"%-15.20s" /* Process name */
"%10u" /* PID */
" %-15.10s" /* Operation */
"%-50.45s" /* Path */
"%-10.10s" /* Result */
" %-200.200s\n", /* Details */
i->pname,
i->pid,
i->operation,
i->path,
i->result,
i->details
);
這是GDB bt
完整輸出:
#0 __strnlen_sse2 () at ../sysdeps/x86_64/multiarch/../strnlen.S:34
No locals.
#1 0x00007ffff7400e09 in _IO_vfprintf_internal (s=s@entry=0x7fffffffdb80, format=<optimized out>,
format@entry=0x402f38 "%-15.20s%10u %-15.10s%-50.45s%-10.10s %-200.200s\n", ap=ap@entry=0x7fffffffdce8) at vfprintf.c:1655
len = <optimized out>
string_malloced = <optimized out>
step0_jumps = {0, -11263, -4214, -4124, -4027, -3937, -3826, -3532, -3116, -2815, -2692, -1937, -2239, -2139, -1766, -16687, 265, 280, 47,
2130, -15904, -28, 883, -5283, -5210, -17380, 567, -2039, -2139, -3638}
space = 0
is_short = 0
use_outdigits = 0
step1_jumps = {0, 0, 0, 0, 0, 0, 0, 0, 0, -2815, -2692, -1937, -2239, -2139, -1766, -16687, 265, 280, 47, 2130, -15904, -28, 883, -5283,
-5210, -17380, 567, -2039, -2139, 0}
group = 0
prec = 10
step2_jumps = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2692, -1937, -2239, -2139, -1766, -16687, 265, 280, 47, 2130, -15904, -28, 883, -5283, -5210,
-17380, 567, -2039, -2139, 0}
string = <optimized out>
left = 1
is_long_double = 0
width = 10
step3a_jumps = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2037, 0, 0, 0, -1766, -16687, 265, 280, 47, 0, 0, 0, 0, -5283, 0, 0, 0, 0, 0, 0}
alt = 0
showsign = 0
is_long = 0
is_char = 0
pad = 32 ' '
step3b_jumps = {0 <repeats 11 times>, -2239, 0, 0, -1766, -16687, 265, 280, 47, 2130, -15904, -28, 883, -5283, -5210, -17380, 567, 0, 0, 0}
step4_jumps = {0 <repeats 14 times>, -1766, -16687, 265, 280, 47, 2130, -15904, -28, 883, -5283, -5210, -17380, 567, 0, 0, 0}
is_negative = <optimized out>
number = <optimized out>
base = <optimized out>
the_arg = {pa_wchar = 0 L'\000', pa_int = 0, pa_long_int = 0, pa_long_long_int = 0, pa_u_int = 0, pa_u_long_int = 0, pa_u_long_long_int = 0,
pa_double = 0, pa_long_double = 0, pa_string = 0x0, pa_wstring = 0x0, pa_pointer = 0x0, pa_user = 0x0}
spec = 115 's'
_buffer = {__routine = 0x1, __arg = 0x7ffff779ac94, __canceltype = 6313844, __prev = 0x7ffff74c3a84 <___vsprintf_chk+148>}
_avail = <optimized out>
thousands_sep = 0x0
grouping = 0xffffffffffffffff <Address 0xffffffffffffffff out of bounds>
done = 91
f = 0x402f5c "s %-200.200s\n"
lead_str_end = 0x402f38 "%-15.20s%10u %-15.10s%-50.45s%-10.10s %-200.200s\n"
end_of_spec = <optimized out>
work_buffer = "\001\200\255\373\000\000\000\000tW`\000\000\000\000\000tW`\000\000\000\000\000tW`\000\000\000\000\000tW`\000\000\000\000\000wW`\000\000\000\000\000\377\377\377\377\377\377\377\377tW`\000\000\000\000\000\377\377\377\377\377\377\377\377", '\000' <repeats 40 times>, "d\000\000\000\004\000\000\000QX`", '\000' <repeats 21 times>, "\020\000\000\000\000\000\000\000CX`\000\000\000\000\000\000\000\000\000[C\033[\000\000\000\000\000\000\000\000\000\330\377\377\377\177\000\000\000\330\377\377\377\177\000\000\377\377\377\377\000\000\000\000"...
workstart = 0x0
workend = 0x7fffffffdb38 "\200\333\377\377\377\177"
ap_save = {{gp_offset = 24, fp_offset = 48, overflow_arg_area = 0x7fffffffddc0, reg_save_area = 0x7fffffffdd00}}
nspecs_done = 4
save_errno = 0
readonly_format = 0
args_malloced = 0x0
specs = 0x7fffffffd670
specs_malloced = false
jump_table = "\001\000\000\004\000\016\000\006\000\000\a\002\000\003\t\000\005\b\b\b\b\b\b\b\b\b\000\000\000\000\000\000\000\032\000\031\000\023\023\023\000\035\000\000\f\000\000\000\000\000\000\025\000\000\000\000\022\000\r\000\000\000\000\000\000\032\000\024\017\023\023\023\n\017\034\000\v\030\027\021\026\f\000\025\033\020\000\000\022\000\r"
__PRETTY_FUNCTION__ = "_IO_vfprintf_internal"
#2 0x00007ffff7427655 in _IO_vsnprintf (
string=0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)",
maxlen=<optimized out>, format=0x402f38 "%-15.20s%10u %-15.10s%-50.45s%-10.10s %-200.200s\n", args=args@entry=0x7fffffffdce8) at vsnprintf.c:119
sf = {f = {_sbf = {_f = {_flags = -72515583,
_IO_read_ptr = 0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)",
_IO_read_base = 0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)",
_IO_write_base = 0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)", _IO_write_ptr = 0x646beb "Ok Read 8 bytes (was requested to read 16)", _IO_write_end = 0x646c20 "\240",
_IO_buf_base = 0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)", _IO_buf_end = 0x646c20 "\240", _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, _markers = 0x0, _chain = 0x0, _fileno = 0,
_flags2 = 0, _old_offset = 4151907146, _cur_column = 0, _vtable_offset = 0 '\000', _shortbuf = "", _lock = 0x0, _offset = 0,
_codecvt = 0x0, _wide_data = 0x0, _freeres_list = 0x0, _freeres_buf = 0x7fff00000000, _freeres_size = 0, _mode = -1,
_unused2 = "\377\177\000\000\000\000\000\024\000\000\000\000\260\260>\367\377\177\000"}, vtable = 0x7ffff7773fa0 <_IO_strn_jumps>},
_s = {_allocate_buffer = 0x0, _free_buffer = 0x650450}},
overflow_buf = "-\a\000\000\000\000\000\000\340\005e\000\000\000\000\000\"\000\000\000\000\000\000\000\"", '\000' <repeats 15 times>, "@Ww\367\377\177\000\000\222\000\000\000\000\000\000\000\060\030@\000\000\000\000"}
ret = <optimized out>
#3 0x00007ffff7408142 in __snprintf (s=<optimized out>, maxlen=<optimized out>, format=<optimized out>) at snprintf.c:34
arg = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7fffffffddd0, reg_save_area = 0x7fffffffdd00}}
done = 10
#4 0x0000000000401d88 in get_str_info (i=0x6441b0) at ui.c:13
tmp_size = 146
tmp = 0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)"
#5 0x0000000000402154 in draw_data (in=0x643dd0) at ui.c:118
s_info = 0x646b90 "0Bd", ' ' <repeats 20 times>, "49 Nd", ' ' <repeats 62 times>, "Ok Read 8 bytes (was requested to read 16)"
i = 10
#6 0x00000000004028c3 in read_from_socket (sock_fd=7) at procmon-viewer.c:276
x = 0x646f10
i = 0x646e10
#7 0x0000000000402671 in main (argc=1, argv=0x7fffffffdfc8) at procmon-viewer.c:192
n = 1
i = 0
ch = -1
sock_fd = 7
efd = 9
stdin_fd = 8
socket_event = {events = 1, data = {ptr = 0x40183000000007, fd = 7, u32 = 7, u64 = 18040992946978823}}
stdin_event = {events = 1, data = {ptr = 0x8, fd = 8, u32 = 8, u64 = 8}}
events = 0x63bb00
我完全迷路了。 這是我第一次看到這樣的回溯。 我為什么得到這個?
我將代碼更新為:
int err;
char *tmp = malloc(win_data_width + 1);
if(!tmp){
return NULL;
}
err = snprintf(tmp,
win_data_width,
"%-15.20s" /* Process name */
"%10u" /* PID */
" %-15.10s" /* Operation */
"%-50.45s" /* Path */
"%-10.10s" /* Result */
" %-200.200s\n", /* Details */
i->pname,
i->pid,
i->operation,
i->path,
i->result,
i->details
);
if(err < 0){
return NULL;
}
而且我仍然遇到完全相同的細分錯誤。 我認為丟棄malloc / snprintf錯誤是合理的。 還有什么可能導致這種情況?
i
是用幾個一個struct char *
和pid_t
(未指針pid_t
)。
每個char *
在調用此函數之前都已進行malloc-ed,並且保證每個char *
都具有應包含的數據或空字符串。 也許i
里面的一些char *
的大小可能大於win_data_width,但是在那種情況下, snprintf
應該截斷內容(這對於我的應用程序是可接受的行為)。
也就是說:我不希望tmp
具有每個char *
所有內容,而是根據win_data_width
的最大可能數據。
您應該進行編碼(如果使用C ++進行編碼)
char *tmp = new char [tmp_size];
(甚至可以使用tmp_size+1
)
或(如果使用普通C編碼)
char* tmp = malloc(tmp_size);
if (!tmp) { perror("malloc"); exit(EXIT_FAILURE); };
char *tmp = new(tmp_size);
應該不應該編譯。 和
char *tmp = new char(tmp_size);
(在C ++中)在初始化為tmp_size
的堆上錯誤地分配了一個char
。
請記住, new
是C ++中的關鍵字。 避免在C中使用該單詞。在純C中具有名為new
的宏或函數的味道很差。
因為有些人甚至只為C代碼使用C ++編譯器。
在許多C程序中,通常總是成功執行malloc
(並在malloc
失敗時終止)的函數通常稱為xmalloc
:
static inline void* xmalloc(size_t sz) {
void* p = malloc(sz);
if (!p) {
fprintf(stderr, "xmalloc failed for %zd bytes: %s\n",
sz, strerror(errno));
exit(EXIT_FAILURE);
};
return p;
}
不要調用new
用C!
順便說一句,始終檢查malloc
是否失敗; 使用內置的ulimit
bash降低內存限制以進行測試。
而且,如果系統具有asprintf(3),則應考慮使用它。
如果您的代碼崩潰了,那么您可能已經損壞了堆內存(在其他地方)。 當然使用valgrind應該會有所幫助。
我認為您需要在調用snprintf()
之前仔細查看所有結構成員的內存分配。 如果有任何空指針,則任何預期為空終止符的字符串操作都將失敗,從而有可能生成段錯誤。
int snprintf (char Target_String[], size_t Buffer_Size, const char Format_String[], ...);
具體細節如下:
snprintf() -根據formatString中的格式說明符將輸出寫入指定的字符串。 在寫入的字符的末尾寫入一個空字符。 (雖然沒有傳遞有關null指針的信息,但這里沒有說) 。
如果生成的格式化字符串大於bufferSize-1個字節長(不包括終止的空字符),則僅第一個bufferSize-1個字符加一個空字符被寫入targetString。 該函數始終返回格式化字符串的完整長度,僅在發生截斷時才大於bufferSize。
這就是為什么建議您始終檢查snprintf()
的輸出的原因(不僅僅是負值)。 解決您對該特定功能的調用時遇到的所有問題,我懷疑您的段錯誤不會發生。
#define WIN_DATA_WIDTH 0x0018
是我在[此處] 9https://chromium.googlesource.com/chromiumos/third_party/kernel-next/+/refs/heads/master/include/pcmcia/cs.h0找到的定義。 我不確定那是否就是您的環境。 0x0018是十進制的24個字節。
[編輯]
按照我在下面說明的操作(最好的方法是,在不了解您如何為struct i的char *成員分配內存的情況下可以做的最好),在這里我沒有segfault的問題:在編譯器中嘗試此操作,然后看看得到了什么。 (當函數返回時, tmp
僅保留malloc分配的24個字節,err設置為303,但沒有segfault)另外,如果我將成員傳遞給I而未分配內存,則struct I
會收到運行時錯誤, 在被引用之前初始化 ,但這不是致命的。 當然總是存在段錯誤。
#include <ansi_c.h>
typedef struct {
char *a;
char *b;
char *c;
char *d;
char *e;
char *f;
char *g;
}I;
int main(void)
{
I k;
k.a = malloc(24); sprintf(k.a, "%f", 12343.432524524);
k.b = malloc(24); sprintf(k.b, "%f", 535.45645646464);
k.c = malloc(24); sprintf(k.c, "%f", 4.4564456645645);
k.d = malloc(24); sprintf(k.d, "%f", 456.644564564564);
k.e = malloc(24); sprintf(k.e, "%f", 5.4564564564564);
k.f = malloc(24); sprintf(k.f, "%f", 45.456456456456);
size_t tmp_size = 0x0018; // win_data_width is the width of a Ncurses window
char *tmp = malloc(tmp_size); // <------- new == malloc MACRO
err = snprintf(tmp,
tmp_size,
"%-15.20s" /* Process name */
"%10u" /* PID */
" %-15.10s" /* Operation */
"%-50.45s" /* Path */
"%-10.10s" /* Result */
" %-200.200s\n", /* Details */
k.a,
k.b,
k.c,
k.d,
k.e,
k.f
); ///////////////////////////////////////
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.