中止陷阱6 问题源于调用extra_info()方法,该方法多次使用strncat()。删除此功能将不会在运行时产生任何错误。
据我了解:
中止陷阱:6是由于使用 指向不存在的内存位置的无效索引 Abort trap: 6 in C Program。 当需要释放可变内存时,也可能发生这种情况。避免 在这种情况下,您可以使用多个变量或释放单个变量 每次重新使用该变量。但是我感觉解决方案要简单得多。
#include <stdio.h>
#include <string.h>
char line[1001]; // The line supports up to a 1000 characters
char lines[11][1001]; // An array of lines (up to 10 lines where each line is a 1000 characters max)
char info[100]; // Holds extra info provided by user
char * extra_info(
char string_1[],
char string_2[],
char string_3[],
char string_4[],
char string_5[]
);
int main(){
int
i, // Line number
j; // Length of the line
char result[100], text[100];
FILE *file;
strcpy(text, "String No."); // The default text
file = fopen("test.txt", "w+"); // Open the file for reading and writing
for(i = 0; i < 10; i++){ // Loop to create a line.
if(i != 9){ // If the line is NOT at the 10th string
sprintf(result, "%s%d, ", text, i); // Format the text and store it in result
}
else{
sprintf(result, "%s%d ", text, i); // Format the text and store it in result
}
extra_info(
"st",
"nd",
"rd",
"th",
"th"
);
strncat(line, info, 100); // Append the extra info at the end of each line
printf("%s", result); // Display the result variable to the screen
strncat(line, result, 15); // Concatenate all strings in one line
}
strncat(line, "\n\n", 2); // Add a new-line character at the end of each line
for(j = 0; j < 10; j++){ // Now loop to change the line
strcpy(lines[i], line); // Copy the line of text into each line of the array
fputs(lines[i], file); // Put each line into the file
}
fclose(file);
}
char * extra_info( // Append user defined and predefined info at the end of a line
char string_1[],
char string_2[],
char string_3[],
char string_4[],
char string_5[]
){
char text[100]; // A variable to hold the text
/* Append a default text into each strings
and concatenate them into one line */
sprintf(text, " 1%s", string_1);
strncat(line, text, 100);
sprintf(text, ", 2%s", string_2);
strncat(line, text, 100);
sprintf(text, ", 3%s", string_3);
strncat(line, text, 100);
sprintf(text, ", 4%s", string_4);
strncat(line, text, 100);
sprintf(text, ", 5%s.", string_5);
strncat(line, text, 100);
strcpy(info, line); // Copies the line into the info global variable
return line;
}
此代码可以使用GCC很好地编译,但是我偶然发现了代码可以正常工作的情况,但是由于该错误可能会破坏某些功能。这与以这种方式多次调用strncat()有关,这使我想到会有内存分配问题,但是在尝试其他示例之后,解决方案似乎简单得多。任何帮助,将不胜感激。预先感谢。
答案 0 :(得分:2)
我在2018年3月编写了随附的代码,以使自己对strncat()
所发生的另一个问题感到满意,这是我在提交答案之前删除的另一个问题。这只是重新定位该代码。
strncat()
功能(如我在comment中所述)是邪恶的。它也与strncpy()
界面不一致-与您在其他任何地方遇到的任何事物都不同。阅读完此内容后,您将(幸运的话)决定永远不要使用strncat()
。
strncat()
C标准定义了strncat()
(并且POSIX同意-strncat()
)
C11§7.24.3.2
strncat
函数简介
#include <string.h> char *strncat(char * restrict s1, const char * restrict s2, size_t n);
说明
strncat
函数从由n
指向的数组到字符串末尾追加不超过s2
个字符(不附加空字符和其后的字符)s1
指向。s2
的初始字符将覆盖s1
结尾的空字符。 309)如果在重叠的对象之间进行复制,则行为是不确定的。返回
strncat
函数返回s1
的值。309)因此,
s1
所指向的数组中可以结尾的最大字符数为strlen(s1)+n+1
。
脚注标识着strncat()
的最大陷阱-您不能安全使用:
char *source = …;
char target[100] = "";
strncat(target, source, sizeof(target));
这与大多数其他函数在C代码中采用数组大小参数 1 的情况相反。
要安全使用strncat()
,您应该知道:
target
sizeof(target)
—或者,对于动态分配的空间,分配的长度strlen(target)
-您必须知道目标字符串中已经存在的长度source
strlen(source)
—如果您担心源字符串是否被截断;如果您不在意,则不需要有了这些信息,您可以使用:
strncat(target, source, sizeof(target) - strlen(target) - 1);
但是,这样做有点愚蠢;如果您知道strlen(target)
,可以避免使用以下方法让strncat()
再次发现它:
strncat(target + strlen(target), source, sizeof(target) - strlen(target) - 1);
请注意,与strncpy()
不同,strncat()
保证了空终止。这意味着您可以使用:
size_t t_size = sizeof(target);
size_t t_length = strlen(target);
strncpy(target + t_length, source, t_size - t_length - 1);
target[t_size - 1] = '\0';
,如果源字符串太长而无法追加到目标,则可以保证得到相同的结果。
说明strncat()
各个方面的多个程序。请注意,在macOS上,strncat()
中有一个<string.h>
的宏定义,该宏调用一个不同的函数__builtin___strncat_chk
-来验证strncat()
的使用。为了使命令行更简洁,我删除了通常使用的两个警告编译器选项--Wmissing-prototypes -Wstrict-prototypes
-但这并不影响任何编译。
strncat19.c
这演示了strncat()
的一种安全用法:
#include <stdio.h>
#include <string.h>
int main(void)
{
char spare1[16] = "abc";
char buffer[16] = "";
char spare2[16] = "xyz";
strncat(buffer, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sizeof(buffer) - 1);
printf("%zu: [%s]\n", strlen(buffer), buffer);
printf("spare1 [%s]\n", spare1);
printf("spare2 [%s]\n", spare2);
return 0;
}
即使设置了严格的警告,它也可以干净地编译(使用XCode 10.1(clang
的Apple Apple LLVM version 10.0.0 (clang-1000.11.45.5)
)和GCC 8.2.0:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror strncat19.c -o strncat19
$ ./strncat19
15: [ABCDEFGHIJKLMNO]
spare1 [abc]
spare2 [xyz]
$
strncat29.c
这类似于strncat19.c
,但是(a)允许您指定要在命令行上复制的字符串,并且(b)错误地使用sizeof(buffer)
而不是sizeof(buffer) - 1
长度。
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
const char *data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (argc == 2)
data = argv[1];
char spare1[16] = "abc";
char buffer[16] = "";
char spare2[16] = "xyz";
strncat(buffer, data, sizeof(buffer));
printf("%zu: [%s]\n", strlen(buffer), buffer);
printf("spare1 [%s]\n", spare1);
printf("spare2 [%s]\n", spare2);
return 0;
}
此代码无法使用严格的警告选项进行编译:
$ clang -O3 -g -std=c11 -Wall -Wextra -Werror strncat29.c -o strncat29
strncat29.c:12:27: error: the value of the size argument in 'strncat' is too large, might lead to a buffer
overflow [-Werror,-Wstrncat-size]
strncat(buffer, data, sizeof(buffer));
^~~~~~~~~~~~~~
strncat29.c:12:27: note: change the argument to be the free space in the destination buffer minus the terminating null byte
strncat(buffer, data, sizeof(buffer));
^~~~~~~~~~~~~~
sizeof(buffer) - strlen(buffer) - 1
1 error generated.
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror strncat29.c -o strncat29
In file included from /usr/include/string.h:190,
from strncat29.c:2:
strncat29.c: In function ‘main’:
strncat29.c:12:5: error: ‘__builtin___strncat_chk’ specified bound 16 equals destination size [-Werror=stringop-overflow=]
strncat(buffer, data, sizeof(buffer));
^~~~~~~
cc1: all warnings being treated as errors
$
即使没有请求警告,警告也是由GCC发出的,但是由于没有-Werror
选项,它会生成可执行文件:
$ gcc -o strncat29 strncat29.c
In file included from /usr/include/string.h:190,
from strncat29.c:2:
strncat29.c: In function ‘main’:
strncat29.c:12:5: warning: ‘__builtin___strncat_chk’ specified bound 16 equals destination size [-Wstringop-overflow=]
strncat(buffer, data, sizeof(buffer));
^~~~~~~
$ ./strncat29
Abort trap: 6
$ ./strncat29 ZYXWVUTSRQPONMK
15: [ZYXWVUTSRQPONMK]
spare1 [abc]
spare2 [xyz]
$ ./strncat29 ZYXWVUTSRQPONMKL
Abort trap: 6
$
这是__builtin__strncat_chk
函数在起作用。
strncat97.c
此代码还带有一个可选的字符串参数;它还要注意命令行上是否还有另一个参数,如果是,它会直接调用strncat()
函数,而不是先让宏对其进行检查:
#include <stdio.h>
#include <string.h>
/*
** Demonstrating that strncat() should not be given sizeof(buffer) as
** the size, even if the string is empty to start with. The use of
** (strncat) inhibits the macro expansion on macOS; the code behaves
** differently when the __strncat_chk function (on High Sierra or
** earlier - it's __builtin__strncat_chk on Mojave) is called instead.
** You get an abort 6 (but no other useful message) when the buffer
** length is too long.
*/
int main(int argc, char **argv)
{
const char *data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (argc >= 2)
data = argv[1];
char spare1[16] = "abc";
char buffer[16] = "";
char spare2[16] = "xyz";
size_t len = (argc == 2) ? sizeof(buffer) : sizeof(buffer) - 1;
if (argc < 3)
strncat(buffer, data, len);
else
(strncat)(buffer, data, len);
printf("buffer %2zu: [%s]\n", strlen(buffer), buffer);
printf("spare1 %2zu: [%s]\n", strlen(spare1), spare1);
printf("spare2 %2zu: [%s]\n", strlen(spare2), spare2);
return 0;
}
现在,编译器产生不同的结果:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror strncat97.c -o strncat97
strncat97.c: In function ‘main’:
strncat97.c:26:9: error: ‘strncat’ output truncated copying 15 bytes from a string of length 26 [-Werror=stringop-truncation]
(strncat)(buffer, data, len);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
$ clang -O3 -g -std=c11 -Wall -Wextra -Werror strncat97.c -o strncat97
$
这展示了使用多个编译器的优势-不同的编译器有时会发现不同的问题。尝试使用不同数量的选项来执行多项操作,此代码很混乱。足以显示:
$ ./strncat97
0x7ffee7506420: buffer 15: [ABCDEFGHIJKLMNO]
0x7ffee7506430: spare1 3: [abc]
0x7ffee7506410: spare2 3: [xyz]
$ ./strncat97 ABCDEFGHIJKLMNOP
Abort trap: 6
$ ./strncat97 ABCDEFGHIJKLMNO
0x7ffeea141410: buffer 15: [ABCDEFGHIJKLMNO]
0x7ffeea141420: spare1 3: [abc]
0x7ffeea141400: spare2 3: [xyz]
$
strncat37.c
这是上面所有程序的完整版本,并且通过getopt()
处理选项。它还使用我的错误报告例程;它们的代码在我的GitHub上的SOQ(堆栈溢出问题)存储库中,作为src/libsoq子目录中的文件stderr.c
和stderr.h
。
#include "stderr.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
/*
** Demonstrating that strncat() should not be given sizeof(buffer) as
** the size, even if the string is empty to start with. The use of
** (strncat) inhibits the macro expansion on macOS; the code behaves
** differently when the __strncat_chk function (on High Sierra or
** earlier - it's __builtin__strncat_chk on Mojave) is called instead.
** You get an abort 6 (but no other useful message) when the buffer
** length is too long.
*/
static const char optstr[] = "fhlmsV";
static const char usestr[] = "[-fhlmsV] [string]";
static const char hlpstr[] =
" -f Function is called directly\n"
" -h Print this help message and exit\n"
" -l Long buffer length -- sizeof(buffer)\n"
" -m Macro cover for the function is used (default)\n"
" -s Short buffer length -- sizeof(buffer)-1 (default)\n"
" -V Print version information and exit\n"
;
int main(int argc, char **argv)
{
err_setarg0(argv[0]);
int f_flag = 0;
int l_flag = 0;
int opt;
while ((opt = getopt(argc, argv, optstr)) != -1)
{
switch (opt)
{
case 'f':
f_flag = 1;
break;
case 'h':
err_help(usestr, hlpstr);
/*NOTREACHED*/
case 'l':
l_flag = 1;
break;
case 'm':
f_flag = 0;
break;
case 's':
l_flag = 0;
break;
case 'V':
err_version(err_getarg0(), &"@(#)$Revision$ ($Date$)"[4]);
/*NOTREACHED*/
default:
err_usage(usestr);
/*NOTREACHED*/
}
}
if (optind < argc - 1)
err_usage(usestr);
const char *data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (optind != argc)
data = argv[optind];
char spare1[16] = "abc";
char buffer[16] = "";
char spare2[16] = "xyz";
size_t len = l_flag ? sizeof(buffer) : sizeof(buffer) - 1;
printf("Specified length: %zu\n", len);
printf("Copied string: [%s]\n", data);
printf("Copied %s\n", f_flag ? "using strncat() function directly"
: "using strncat() macro");
if (f_flag)
(strncat)(buffer, data, len);
else
strncat(buffer, data, len);
printf("%p: buffer %2zu: [%s]\n", (void *)buffer, strlen(buffer), buffer);
printf("%p: spare1 %2zu: [%s]\n", (void *)spare1, strlen(spare1), spare1);
printf("%p: spare2 %2zu: [%s]\n", (void *)spare2, strlen(spare2), spare2);
return 0;
}
和以前一样,Clang和GCC对代码的可接受性有不同的看法(-Werror
表示来自GCC的警告被视为错误):
$ clang -O3 -g -I./inc -std=c11 -Wall -Wextra -Werror strncat37.c -o strncat37 -L./lib -lsoq
$ gcc -O3 -g -I./inc -std=c11 -Wall -Wextra -Werror strncat37.c -o strncat37 -L./lib -lsoq
strncat37.c: In function ‘main’:
strncat37.c:80:9: error: ‘strncat’ output may be truncated copying between 15 and 16 bytes from a string of length 26 [-Werror=stringop-truncation]
(strncat)(buffer, data, len);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
$
运行时:
$ ./strncat37 -h
Usage: strncat37 [-fhlmsV] [string]
-f Function is called directly
-h Print this help message and exit
-l Long buffer length -- sizeof(buffer)
-m Macro cover for the function is used (default)
-s Short buffer length -- sizeof(buffer)-1 (default)
-V Print version information and exit
$ ./strncat37
Specified length: 15
Copied string: [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
Copied using strncat() macro
0x7ffedff4e400: buffer 15: [ABCDEFGHIJKLMNO]
0x7ffedff4e410: spare1 3: [abc]
0x7ffedff4e3f0: spare2 3: [xyz]
$ ./strncat37 -m -s
Specified length: 15
Copied string: [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
Copied using strncat() macro
0x7ffeeaf043f0: buffer 15: [ABCDEFGHIJKLMNO]
0x7ffeeaf04400: spare1 3: [abc]
0x7ffeeaf043e0: spare2 3: [xyz]
$ ./strncat37 -m -l
Specified length: 16
Copied string: [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
Copied using strncat() macro
Abort trap: 6
$ ./strncat37 -f -s
Specified length: 15
Copied string: [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
Copied using strncat() function directly
0x7ffeef0913f0: buffer 15: [ABCDEFGHIJKLMNO]
0x7ffeef091400: spare1 3: [abc]
0x7ffeef0913e0: spare2 3: [xyz]
$ ./strncat37 -f -l
Specified length: 16
Copied string: [ABCDEFGHIJKLMNOPQRSTUVWXYZ]
Copied using strncat() function directly
0x7ffeed8d33f0: buffer 16: [ABCDEFGHIJKLMNOP]
0x7ffeed8d3400: spare1 0: []
0x7ffeed8d33e0: spare2 3: [xyz]
$
默认行为也是正确的行为;该程序不会崩溃,也不会产生意外的副作用。当使用宏运行并且指定的长度太长(-m -l
)时,程序崩溃。当使用该函数并且长度太长(-f -l
)运行时,程序将在spare1
末尾添加空值的情况下覆盖数组buffer
的第一个字节,并显示16个字节的数据而不是15。
1 当您使用scanf()
或类似方法时,%31s
中有一个例外;指定的数字是可以存储在字符串中的非空字符的数目;读取其他31个字符后,它将添加一个空字节。同样,可以安全使用的最大大小为sizeof(string) - 1
。
您可以在我的GitHub上的SOQ子目录的src/so-5405-4423(堆栈溢出问题)存储库中找到strncatXX.c
的代码。
从问题中获取代码,并将int main(){
更改为int main(void){
,因为我的默认编译选项会生成错误(如果我不使用-Werror
,则会出现警告)非原型main()
,并在return 0;
的末尾添加main()
,剩下的就是这些错误,这些错误使我在运行macOS 10.14.2 Mojave的Mac上使用GCC 8.2.0进行编译:>
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes so-5405-4423-v1.c -o so-5405-4423-v1
In file included from /opt/gcc/v8.2.0/lib/gcc/x86_64-apple-darwin17.7.0/8.2.0/include-fixed/stdio.h:425,
from so-5405-4423-v1.c:1:
so-5405-4423-v1.c: In function ‘main’:
so-5405-4423-v1.c:32:29: error: ‘%d’ directive writing between 1 and 2 bytes into a region of size between 1 and 100 [-Werror=format-overflow=]
sprintf(result, "%s%d, ", text, i); // Format the text and store it in result
^~~~~~~~
so-5405-4423-v1.c:32:29: note: directive argument in the range [0, 10]
so-5405-4423-v1.c:32:13: note: ‘__builtin___sprintf_chk’ output between 4 and 104 bytes into a destination of size 100
sprintf(result, "%s%d, ", text, i); // Format the text and store it in result
^~~~~~~
so-5405-4423-v1.c:37:29: error: ‘ ’ directive writing 1 byte into a region of size between 0 and 99 [-Werror=format-overflow=]
sprintf(result, "%s%d ", text, i); // Format the text and store it in result
^~~~~~~
so-5405-4423-v1.c:37:13: note: ‘__builtin___sprintf_chk’ output between 3 and 102 bytes into a destination of size 100
sprintf(result, "%s%d ", text, i); // Format the text and store it in result
^~~~~~~
cc1: all warnings being treated as errors
$
编译器注意到text
是一个可以包含0到99个字符的字符串,因此从理论上讲,当与数字和", "
(或{{1} }进行一次迭代)。将其初始化为" "
的事实意味着不存在溢出风险,但是您可以通过为"String No."
使用较短的长度来缓解这种情况,例如用text
代替{{1 }}。
我承认,这个警告在GCC中是相对较新的,并不总是那么有用(这是代码正常的情况,但是警告仍然出现)。我通常会做来解决该问题,仅是因为该问题当前会以我的默认选项显示,并且代码无法使用20
进行任何警告编译,并且我不准备这样做保护等级。我不使用100
的{{1}}选项raw;它会产生绝对适得其反的警告(至少是AFAIAC)。但是,我反对对我不起作用的“所有”选项。如果出于某种原因,-Werror
或clang
选项太痛苦了,我会反抗,但要谨慎。我会检查疼痛程度,并针对任何症状进行处理。
您也有循环:
-Weverything
不幸的是,运行此循环时,-Wall
等于-Wextra
,它超出了数组for(j = 0; j < 10; j++){ // Now loop to change the line
strcpy(lines[i], line); // Copy the line of text into each line of the array
fputs(lines[i], file); // Put each line into the file
}
的范围。这可能导致崩溃。假定索引应该是i
而不是10
。
这是您的代码的测试版本(lines
)
j
运行时,它产生的输出类似于:
i
当您发现214个字节从so-5405-4423-v2.c
(足够容纳该字符串)被复制到#include <stdio.h>
#include <string.h>
char line[1001];
char lines[11][1001];
char info[100];
char *extra_info(char string_1[], char string_2[], char string_3[],
char string_4[], char string_5[]);
int main(void)
{
char result[100], text[20];
const char filename[] = "test.txt";
FILE *file;
strcpy(text, "String No.");
file = fopen(filename, "w+");
if (file == NULL)
{
fprintf(stderr, "Failed to open file '%s' for writing/update\n", filename);
return 1;
}
for (int i = 0; i < 10; i++)
{
if (i != 9)
sprintf(result, "%s%d, ", text, i);
else
sprintf(result, "%s%d ", text, i);
fprintf(stderr, "Iteration %d:\n", i);
fprintf(stderr, "1 result (%4zu): [%s]\n", strlen(result), result);
fprintf(stderr, "1 line (%4zu): [%s]\n", strlen(line), line);
extra_info("st", "nd", "rd", "th", "th");
fprintf(stderr, "2 line (%4zu): [%s]\n", strlen(line), line);
fprintf(stderr, "1 info (%4zu): [%s]\n", strlen(info), info);
strncat(line, info, 100);
fprintf(stderr, "3 line (%4zu): [%s]\n", strlen(line), line);
printf("%s", result);
strncat(line, result, 15);
fprintf(stderr, "3 line (%4zu): [%s]\n", strlen(line), line);
}
fprintf(stderr, "4 line (%4zu): [%s]\n", strlen(line), line);
strncat(line, "\n\n", 2);
for (int j = 0; j < 10; j++)
{
strcpy(lines[j], line);
fputs(lines[j], file);
}
fclose(file);
return 0;
}
char *extra_info(char string_1[], char string_2[], char string_3[],
char string_4[], char string_5[])
{
char text[100];
sprintf(text, " 1%s", string_1);
fprintf(stderr, "EI 1: add (%zu) [%s] to (%zu) [%s]\n", strlen(string_1), string_1, strlen(line), line);
strncat(line, text, 100);
sprintf(text, ", 2%s", string_2);
fprintf(stderr, "EI 2: add (%zu) [%s] to (%zu) [%s]\n", strlen(string_2), string_2, strlen(line), line);
strncat(line, text, 100);
sprintf(text, ", 3%s", string_3);
fprintf(stderr, "EI 3: add (%zu) [%s] to (%zu) [%s]\n", strlen(string_3), string_3, strlen(line), line);
strncat(line, text, 100);
sprintf(text, ", 4%s", string_4);
fprintf(stderr, "EI 4: add (%zu) [%s] to (%zu) [%s]\n", strlen(string_4), string_4, strlen(line), line);
strncat(line, text, 100);
sprintf(text, ", 5%s.", string_5);
fprintf(stderr, "EI 5: add (%zu) [%s] to (%zu) [%s]\n", strlen(string_5), string_5, strlen(line), line);
strncat(line, text, 100);
fprintf(stderr, "EI 6: copy (%zu) [%s] to info\n", strlen(line), line);
strcpy(info, line);
return line;
}
(不是—它长100个字节)时,随之而来的崩溃是并不奇怪。尚不清楚所需的行为是什么。
在我的Mac上,Iteration 0:
1 result ( 13): [String No.0, ]
1 line ( 0): []
EI 1: add (2) [st] to (0) []
EI 2: add (2) [nd] to (4) [ 1st]
EI 3: add (2) [rd] to (9) [ 1st, 2nd]
EI 4: add (2) [th] to (14) [ 1st, 2nd, 3rd]
EI 5: add (2) [th] to (19) [ 1st, 2nd, 3rd, 4th]
EI 6: copy (25) [ 1st, 2nd, 3rd, 4th, 5th.] to info
2 line ( 25): [ 1st, 2nd, 3rd, 4th, 5th.]
1 info ( 25): [ 1st, 2nd, 3rd, 4th, 5th.]
3 line ( 50): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.]
3 line ( 63): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, ]
Iteration 1:
1 result ( 13): [String No.1, ]
1 line ( 63): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, ]
EI 1: add (2) [st] to (63) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, ]
EI 2: add (2) [nd] to (67) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st]
EI 3: add (2) [rd] to (72) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd]
EI 4: add (2) [th] to (77) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd]
EI 5: add (2) [th] to (82) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th]
EI 6: copy (88) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.] to info
2 line ( 88): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.]
1 info ( 88): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.]
3 line ( 176): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.]
3 line ( 189): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, ]
Iteration 2:
1 result ( 13): [String No.2, ]
1 line ( 189): [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, ]
EI 1: add (2) [st] to (189) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, ]
EI 2: add (2) [nd] to (193) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, 1st]
EI 3: add (2) [rd] to (198) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, 1st, 2nd]
EI 4: add (2) [th] to (203) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, 1st, 2nd, 3rd]
EI 5: add (2) [th] to (208) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, 1st, 2nd, 3rd, 4th]
EI 6: copy (214) [ 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th. 1st, 2nd, 3rd, 4th, 5th.String No.0, 1st, 2nd, 3rd, 4th, 5th.String No.1, 1st, 2nd, 3rd, 4th, 5th.] to info
String No.0, String No.1, Abort trap: 6
调试器在line
中报告崩溃; AFAICT,它位于info
末尾突出显示的行中:
lldb
因此,虽然显然不是__strcpy_chk
导致崩溃,但是extra_info()
的使用方式显然不是正确的-IMO,这是不正确的,但是看法可能会有所不同。我仍然坚持我的基本结论:请勿使用frame #6: 0x00007fff681bbe84 libsystem_c.dylib`__strcpy_chk + 83
frame #7: 0x00000001000017cc so-5405-4423-v2`extra_info(string_1=<unavailable>, string_2=<unavailable>, string_3="rd", string_4="th", string_5="th") at so-5405-4423-v2.c:86
。
答案 1 :(得分:-1)
解决方案很简单,因为我感觉到,在C语言中根本没有邪恶,邪恶或愤世嫉俗的现象。所有strcpy()的第1个都不需要发生,第2个extra_info()出于其目的而被放错了位置,第3个即使我要使用strcpy()来交换参数也是如此。因此,错误中止陷阱6 :
<img src="//colinbendell.cloudinary.com/image/upload/c_crop,f_auto,g_auto,h_350,w_400/v1512090971/Wizard-Clap-by-Markus-Magnusson.gif" id="gif1" alt="1.gif" style="width:400px;height:400px;border:1px solid black;" />