admin 管理员组

文章数量: 887021

c语言字符串缺少终止符,c

c-为什么strncpy不为null终止?

strncpy()应该可以防止缓冲区溢出。 但是,如果它可以防止溢出而不终止为null,则很可能随后的字符串操作都会溢出。 因此,为了防止这种情况,我发现自己正在做:

strncpy( dest, src, LEN );

dest[LEN - 1] = '\0';

strncpy()提供:

strncpy()函数与之类似,只是复制的src字节数不超过n个。 因此,如果src的前n个字节中没有空字节,则结果将不会以空值结尾。

在没有null终止的情况下,看起来像是无辜的事情如下:

printf( "FOO: %s\n", dest );

...可能会崩溃。

是否有strncpy()更好,更安全的替代品?

Timothy Pratley asked 2019-09-28T03:04:45Z

11个解决方案

41 votes

strncat不能用作更安全的strncpy,应该用于将一个字符串插入另一个字符串的中间。

所有这些“安全”字符串处理功能(例如strncat和strncpy)都是已在以后的标准中添加的修补程序,以减轻缓冲区溢出漏洞等。

Wikipedia提到strncat作为编写自己的安全strncpy的替代方法:

*dst = '\0'; strncat(dst, src, LEN);

编辑

我错过了strncat在以空字符终止时,如果字符串长于或等于LEN char,则超过LEN个字符。

无论如何,使用strncat代替任何本地解决方案(例如memcpy(...,strlen(...))/)的意义在于,strncat的实现可能是库中目标/平台优化的。

当然,您需要检查dst是否至少包含nullchar,因此正确使用strncat的方法如下:

if(LEN) { *dst = '\0'; strncat(dst, src, LEN-1); }

我也承认strncpy对于将子字符串复制到另一个字符串不是很有用,如果src比n char短,则目标字符串将被截断。

Ernelli answered 2019-09-28T03:05:42Z

23 votes

已经有像strlcpy这样的开源实现可以进行安全复制。

[]

在参考文献中有到资源的链接。

StampedeXV answered 2019-09-28T03:06:21Z

23 votes

最初,第7版UNIX文件系统(请参见DIR(5))具有目录条目,该目录条目将文件名限制为14个字节。 目录中的每个条目都由2个字节的inode编号和14个字节的名称组成,将null填充为14个字符,但不一定以null结尾。 我相信strncpy()是为与这些目录结构一起使用而设计的,或者至少可以完美地用于该目录结构。

考虑:

14个字符的文件名不能为空终止。

如果名称少于14个字节,则将其空填充为全长(14个字节)。

这正是通过以下方式实现的:

strncpy(inode->d_name, filename, 14);

因此,strncpy()非常适合其原始利基应用。 巧合的是,防止以null终止的字符串溢出。

(请注意,将空值填充到长度14并不是一个严重的开销-如果缓冲区的长度为4 KB,而您想要的只是安全地将20个字符复制到其中,那么额外的4075个空值将是严重的矫kill过正,并且很容易 如果您将材料反复添加到较长的缓冲区中,则会导致二次行为。)

Jonathan Leffler answered 2019-09-28T03:07:23Z

8 votes

ISO / IEC TR 24731中指定了一些新的替代方法(有关信息,请检查[.html])。 这些函数中的大多数都带有一个附加参数,该参数指定目标变量的最大长度,确保所有字符串都以null终止,并以strcpy_s()656结尾(以“ safe”表示),以区别于它们之前的“ unsafe”名称。versions.1

不幸的是,他们仍在获得支持,可能不适用于您的特定工具集。 如果您使用旧的不安全功能,则更高版本的Visual Studio将引发警告。

如果您的工具不支持新功能,则为旧功能创建自己的包装器应该很容易。 这是一个例子:

errCode_t strncpy_safe(char *sDst, size_t lenDst,

const char *sSrc, size_t count)

{

// No NULLs allowed.

if (sDst == NULL || sSrc == NULL)

return ERR_INVALID_ARGUMENT;

// Validate buffer space.

if (count >= lenDst)

return ERR_BUFFER_OVERFLOW;

// Copy and always null-terminate

memcpy(sDst, sSrc, count);

*(sDst + count) = '\0';

return OK;

}

您可以更改功能以满足自己的需要,例如,始终复制尽可能多的字符串而不会溢出。 实际上,如果将strcpy_s()传递为count,则VC ++实现可以做到这一点。

1当然,您仍然需要准确了解目标缓冲区的大小:如果您提供3个字符的缓冲区,但告诉strcpy_s()它有25个字符的空间,您仍然会遇到麻烦。

Adam Liss answered 2019-09-28T03:08:17Z

7 votes

Strncpy可以更安全地防止程序用户的堆栈溢出攻击,它不能保护您免受程序员所犯的错误的影响,例如按照您所描述的方式打印非空终止的字符串。

您可以通过限制printf打印的字符数来避免由于描述的问题而崩溃:

char my_string[10];

//other code here

printf("%.9s",my_string); //limit the number of chars to be printed to 9

Liran Orevi answered 2019-09-28T03:08:51Z

5 votes

使用strlcpy()(在此处指定):[.html]

如果您的libc没有实现,请尝试以下一种:

size_t strlcpy(char* dst, const char* src, size_t bufsize)

{

size_t srclen =strlen(src);

size_t result =srclen; /* Result is always the length of the src string */

if(bufsize>0)

{

if(srclen>=bufsize)

srclen=bufsize-1;

if(srclen>0)

memcpy(dst,src,srclen);

dst[srclen]='\0';

}

return result;

}

(我于2004年撰写-致力于公共领域。)

alex tingle answered 2019-09-28T03:09:31Z

3 votes

strncpy直接与可用的字符串缓冲区一起使用,如果您直接与内存一起使用,则现在必须缓冲区大小,并且可以手动设置'\ 0'。

我相信普通C语言中没有更好的替代方法,但是如果您在处理原始内存时要格外小心,它的确不是那么糟糕。

Arkaitz Jimenez answered 2019-09-28T03:10:06Z

3 votes

您可以使用size-1代替size-1

snprintf(buffer, BUFFER_SIZE, "%s", src);

这是一个单行代码,最多将2545145963619025925920个非空字符从src复制到dest,并添加一个空终止符:

static inline void cpystr(char *dest, const char *src, size_t size)

{ if(size) while((*dest++ = --size ? *src++ : 0)); }

Christoph answered 2019-09-28T03:10:41Z

3 votes

我一直喜欢:

memset(dest, 0, LEN);

strncpy(dest, src, LEN - 1);

进行后续修复,但这实际上只是一个优先事项。

stonemetal answered 2019-09-28T03:11:19Z

2 votes

这些功能的发展远不止是设计,因此确实没有“为什么”。您只需要学习“如何”。 不幸的是,Linux手册页至少是缺少这些功能的常见用例示例,我注意到很多我审查过的代码中的滥用问题。 我在这里做了一些笔记:[.html]

pixelbeat answered 2019-09-28T03:11:49Z

2 votes

在不依赖更新的扩展的情况下,我过去做过这样的事情:

/* copy N "visible" chars, adding a null in the position just beyond them */

#define MSTRNCPY( dst, src, len) ( strncpy( (dst), (src), (len)), (dst)[ (len) ] = '\0')

甚至:

/* pull up to size - 1 "visible" characters into a fixed size buffer of known size */

#define MFBCPY( dst, src) MSTRNCPY( (dst), (src), sizeof( dst) - 1)

为什么用宏而不是较新的“内置”(?)函数? 因为过去有很多不同的unice,以及其他每天在执行C语言时必须移植回的非unix(非Windows)环境。

Roboprog answered 2019-09-28T03:12:30Z

本文标签: c语言字符串缺少终止符 c