Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
strncpy不';不总是空终止_C_Strncpy - Fatal编程技术网

strncpy不';不总是空终止

strncpy不';不总是空终止,c,strncpy,C,Strncpy,我使用的代码如下: char filename[ 255 ]; strncpy( filename, getenv( "HOME" ), 235 ); strncat( filename, "/.config/stationlist.xml", 255 ); 获取此消息: (warning) Dangerous usage of strncat - 3rd parameter is the maximum number of characters to append. (error) Dang

我使用的代码如下:

char filename[ 255 ];
strncpy( filename, getenv( "HOME" ), 235 );
strncat( filename, "/.config/stationlist.xml", 255 );
获取此消息:

(warning) Dangerous usage of strncat - 3rd parameter is the maximum number of characters to append.
(error) Dangerous usage of 'filename' (strncpy doesn't always null-terminate it).

您的
strncat
调用可能会溢出
filename

使用:

另外,请确保在调用
strncpy
后将缓冲区终止为空:

strncpy( filename, getenv( "HOME" ), 235 );
filename[235] = '\0';

由于
strncpy
不为空,因此,如果源的长度大于或等于要复制的最大字符数,则终止其目标缓冲区。

man strncpy
有这样的说法:

Warning: If there is no null byte among the first n bytes
of src, the string placed in dest will not be null terminated.
如果它在耗尽最大长度之前在源中遇到0字节,则将复制它。但如果在源中的第一个0之前达到最大长度,则不会终止目标。最好确保在strncpy()返回…

1)您的strncpy不一定为空终止文件名之后是您自己。事实上,如果getenv(“HOME”)长度超过235个字符,并且getenv(“HOME”)[234]不是0,那么它就不会是0。 2) 您的strncat()可能会尝试将文件名扩展到255个字符以外,因为正如它所说

3rd parameter is the maximum number of characters to append. 

(不是dst的总允许长度)

我通常避免使用
str*cpy()
str*cat()
。您必须处理边界条件、神秘的API定义和意外的性能后果

您可以改用
snprintf()
。您只需要处理目标缓冲区的大小。而且,它更安全,因为它不会溢出,并且将始终为您NUL终止

char filename[255];
const char *home = getenv("HOME");
if (home == 0) home = ".";
int r = snprintf(filename, sizeof(filename), "%s%s", home, "/.config/stationlist.xml");
if (r >= sizeof(filename)) {
    /* need a bigger filename buffer... */
} else if (r < 0) {
    /* handle error... */
}
char文件名[255];
const char*home=getenv(“home”);
如果(home==0)home=“.”;
int r=snprintf(文件名,sizeof(文件名),“%s%s”,home,“/.config/stationlist.xml”);
如果(r>=sizeof(文件名)){
/*需要更大的文件名缓冲区*/
}else如果(r<0){
/*处理错误*/
}
两个
strncpy()
和(更重要的是)
strncat()
都有不明显的行为,最好不要使用它们

strncpy() 如果您的目标字符串长度为255字节(为了参数),则
strncpy()
将始终写入所有255字节。如果源字符串短于255个字节,它将对剩余的字符串进行零填充。如果源字符串长度超过255字节,则在255字节后将停止复制,使目标字符串没有空终止符

strncat() 大多数“size”函数(
strncpy()
memcpy()
memmove()
)等)的大小参数是目标字符串(内存)中的字节数。使用
strncat()
,大小是目标中已经存在的字符串结束后剩余的空间量。因此,只有当您知道目标缓冲区有多大(
S
)以及目标字符串当前有多长(
L
)时,才能安全地使用
strncat()。然后,
strncat()
的安全参数是
S-L
(我们将担心在其他时间是否有一个off)。但是如果您知道
L
,那么让
strncat()
跳过
L
字符是没有意义的;您可以将
target+L
作为起点,然后简单地复制数据。您可以使用
memmove()
memcpy()
,也可以使用
strcpy()
,甚至
strncpy()
。如果您不知道源字符串的长度,您必须确信截断它是有意义的

问题代码的分析 第一行是无懈可击的,除非大小被认为太小(或者您在未设置
$HOME
的上下文中运行程序),但这超出了这个问题的范围。调用
strncpy()
不会使用
sizeof(filename)
作为大小,而是使用任意小的数字。这并不是世界末日,但不能保证变量的最后20个字节通常是零字节(甚至其中任何一个都是零字节)。在某些情况下(
filename
是一个全局变量,以前未使用过),可以保证零

strncat()
调用尝试在
filename
中的字符串末尾追加24个字符,这些字符可能已经是232-234字节长,或者可能任意超过235字节。无论哪种方式,这都是有保证的缓冲区溢出。
strncat()
的使用也直接陷入了关于其大小的陷阱。您已经说过,在
文件名
中已有字符的末尾之外再加上255个字符是可以的,这显然是错误的(除非
getenv(“HOME”)
中的字符串恰好是空的)

安全代码:

char filename[255];
static const char config_file[] = "/.config/stationlist.xml";
const char *home = getenv("HOME");
size_t len = strlen(home);
if (len > sizeof(filename) - sizeof(config_file))
    ...error file name will be too long...
else
{
    memmove(filename, home, len);
    memmove(filename+len, config_file, sizeof(config_file));
}
有些人会坚持认为“
memcpy()
是安全的,因为字符串不能重叠”,在某种程度上它们是正确的,但重叠应该是无问题的,对于
memmove()
,这是无问题的。因此,我一直在使用
memmove()
,但我还没有进行计时测量,以确定这是一个多大的问题,如果这是一个问题的话。也许其他人做了测量

总结
  • 不要使用
    strncat()
  • 小心地使用strncpy()
  • (注意它在非常大的缓冲区上的行为!)
  • 计划改用
    memmove()
    memcpy()
    ;如果你能安全地复制,你就知道使这变得合理所需的尺寸

  • strncpy(复制到、复制自、输入大小)
    在字符数组后输出垃圾值(不用于字符串类型)。要解决它的输出,请使用遍历字符数组的for循环,而不是简单地使用
    coutwhat是您的实际问题?很好奇,但是哪个编译器给出了这些消息?@andrewcooke谷歌说它是
    cppcheck
    静态分析器谢谢。看起来很有用。getenv()的危险用法:它可能返回NULL,并导致str[n]cpy()的危险用法;如果filename是一个自动变量,则不会对其进行初始化(或者您称之为零)
    char filename[255];
    strncpy(filename, getenv("HOME"), 235);
    strncat(filename, "/.config/stationlist.xml", 255);
    
    char filename[255];
    static const char config_file[] = "/.config/stationlist.xml";
    const char *home = getenv("HOME");
    size_t len = strlen(home);
    if (len > sizeof(filename) - sizeof(config_file))
        ...error file name will be too long...
    else
    {
        memmove(filename, home, len);
        memmove(filename+len, config_file, sizeof(config_file));
    }
    
    for(i=0;i<size;i++){cout<<var[i]}