strncpy()据说可以防止缓冲区溢出.但是如果它在没有null终止的情况下防止溢出,那么随后的字符串操作将会溢出.所以为了防止这种情况,我发现自己在做:
strncpy( dest, src, LEN );
dest[LEN - 1] = '\0';
Run Code Online (Sandbox Code Playgroud)
man strncpy 得到:
strncpy()函数类似,只是复制了不超过n个字节的src.因此,如果src的前n个字节中没有空字节,则结果将不会以空值终止.
没有null终止看似无辜的东西,如:
printf( "FOO: %s\n", dest );
Run Code Online (Sandbox Code Playgroud)
......可能会崩溃
是否有更好,更安全的替代品strncpy()?
Ern*_*lli 41
strncpy不打算用作更安全的strcpy,它应该用于在另一个中间插入一个字符串.
所有那些"安全"的字符串处理函数,例如snprintf并且vsnprintf是在以后的标准中添加的修复,以减轻缓冲区溢出漏洞等.
维基百科提到strncat作为编写自己的安全的替代方法strncpy:
*dst = '\0'; strncat(dst, src, LEN);
Run Code Online (Sandbox Code Playgroud)
编辑
我错过了strncat超过LEN字符,当null终止字符串时,如果它长于或等于LEN char的话.
无论如何,使用strncat代替任何自行开发的解决方案,例如memcpy(...,strlen(...))/无论strncat的实现可能是库中的目标/平台优化.
当然你需要检查dst是否至少保存了nullchar,所以正确使用strncat会是这样的:
if(LEN) { *dst = '\0'; strncat(dst, src, LEN-1); }
Run Code Online (Sandbox Code Playgroud)
我还承认strncpy对于将子字符串复制到另一个字符串并不是很有用,如果src比n字符短,则目标字符串将被截断.
Sta*_*eXV 24
已经有像strlcpy这样的开源实现可以进行安全复制.
http://en.wikipedia.org/wiki/Strlcpy
在参考文献中有链接到源.
Jon*_*ler 24
最初,第7版UNIX文件系统(参见DIR(5))具有将文件名限制为14个字节的目录条目; 目录中的每个条目由2个字节组成,用于inode编号加上14个字节用于名称,null填充为14个字符,但不一定是以null结尾.我的信念strncpy()是设计用于那些目录结构 - 或者至少,它适用于该结构.
考虑:
这正是通过以下方式实现的目标:
strncpy(inode->d_name, filename, 14);
Run Code Online (Sandbox Code Playgroud)
因此,strncpy()理想地适合其原始的利基应用.巧合的是,防止以null结尾的字符串溢出.
(注意,长度为14的空填充不是一个严重的开销 - 如果缓冲区的长度是4 KB并且你想要的只是安全地复制20个字符,那么额外的4075个空值是严重的过度杀伤,并且可以很容易如果您反复向长缓冲区添加材料,则会导致二次行为.)
ISO/IEC TR 24731中规定了一些新的替代方案(请访问https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/317-BSI.html获取信息).这些函数中的大多数都使用一个额外的参数来指定目标变量的最大长度,确保所有字符串都以空值终止,并且名称以_s(以"安全"?)结尾以区别于它们之前的"不安全"版本.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;
}
Run Code Online (Sandbox Code Playgroud)
您可以更改功能以满足您的需要,例如,始终尽可能多地复制字符串而不会溢出.事实上,如果你通过VC++实现可以做到这一点_TRUNCATE的count.
strcpy_s()它有25个字符的空间,那么您仍然遇到麻烦.
strncpy()函数是通过对栈溢出攻击的安全用户程序的,它并不能保护你避免发生差错,你的程序员做的,比如打印一个非空结尾的字符串,你所描述的方式.
您可以通过限制printf打印的字符数来避免因您所描述的问题而崩溃:
char my_string[10];
//other code here
printf("%.9s",my_string); //limit the number of chars to be printed to 9
Run Code Online (Sandbox Code Playgroud)
使用strlcpy(),在这里指定:http://www.courtesan.com/todd/papers/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;
}
Run Code Online (Sandbox Code Playgroud)
(2004年由我撰写 - 致力于公共领域.)
strncpy()您可以使用
snprintf(buffer, BUFFER_SIZE, "%s", src);
Run Code Online (Sandbox Code Playgroud)
这是一个单行代码,它从to复制最多size-1非空字符并添加一个空终止符:srcdest
static inline void cpystr(char *dest, const char *src, size_t size)
{ if(size) while((*dest++ = --size ? *src++ : 0)); }
Run Code Online (Sandbox Code Playgroud)