strncpy复制超过指定的大小 [英] strncpy copying more than the specified size

查看:220
本文介绍了strncpy复制超过指定的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下示例代码模仿了应用程序中的代码.

I have the following sample code that mimics the code in the application.

#include <iostream>
#include <string.h>
#include <cstring>
#include <atlstr.h>
using namespace std;

    void test(char *s, int size)
    {
        //s = "";
        int lens = strlen(s);
        char *str1 = "(( State:0.000000 Std30c5  =  State:T ) OR (( State:0.000000 Std30c6  =  State:T )  OR (( State:0.000000 Std30c7  =  State:T ) OR (( State:0.000000 Std30c8  =  State:T ) OR (( State:0.000000 Std30c9  =  State:T ) OR (( State:0.000000 Std30ca  =  State:T ) OR (( State:0.000000 Std30cb  =  State:T ) OR (( State:0.000000 Std30cc  =  State:T ) OR (( State:0.000000 Std30cd  =  State:T ) OR (( State:0.000000 Std30ce  =  State:T ) OR (( State:0.000000 Std30cf  =  State:T ) OR ( ...0.000000   =  State:T ))))))))))))";
        int len1 = strlen(str1);
        strncpy(s, str1, 512);
        int len = strlen(s);

    }

    int main()
    {

        char strDisplay[512] = "";
        test(strDisplay, 512);


        cout << strDisplay << endl;
        system("pause");
        return 0;
    }

结果是: lenofstrtest = 523; lenofstr1 = 512;

Result is : lenofstrtest = 523; lenofstr1 = 512;

strtest =(((State:0.000000 Std30c5 = State:T)OR((State:0.000000 Std30c6 = State:T)OR((State:0.000000 Std30c7 = State:T)OR((State:0.000000 Std30c7 = State:T)OR((State:0.000000 Std30c7 = State:T) :T)OR((状态:0.000000 Std30c9 =状态:T)OR((状态:0.000000 Std30ca =状态:T)OR((状态:0.000000 Std30cb =状态:T)OR((状态:0.000000 Std30cb =状态:T )OR((State:0.000000 Std30cd = State:T)OR((State:0.000000 Std30ce = State:T)OR((State:0.000000 Std30cf = State:T)OR(... 0.000000 = State:T))) ))))))))))ÌÌÌÌJ¢Š£øø)"

strtest = "(( State:0.000000 Std30c5 = State:T ) OR (( State:0.000000 Std30c6 = State:T ) OR (( State:0.000000 Std30c7 = State:T ) OR (( State:0.000000 Std30c8 = State:T ) OR (( State:0.000000 Std30c9 = State:T ) OR (( State:0.000000 Std30ca = State:T ) OR (( State:0.000000 Std30cb = State:T ) OR (( State:0.000000 Std30cc = State:T ) OR (( State:0.000000 Std30cd = State:T ) OR (( State:0.000000 Std30ce = State:T ) OR (( State:0.000000 Std30cf = State:T ) OR ( ...0.000000 = State:T ))))))))))))ÌÌÌÌJ¢Š£øø)"

为什么strncpy复制其他字符?

Why is strncpy copying additional characters?

(这会引起问题,因为错误的strnlen会导致拆包逻辑陷入困境!)

(This is causing an issue since the incorrect strnlen is causing the unpacking logic to go haywire!)

我想这与"strncpy bug 512 bytes"有关...请帮助我理解此bug.

I guess this is related to "strncpy bug 512 bytes"...please help me understand this bug.

推荐答案

strncpy不会在截断的字符串中添加终止符'\ 0',这会导致出现您遇到的问题.如果字符串未正确终止,则它看起来会更长一些,但是实际上看到的是放在内存中的缓冲区之后的数据.可能会导致严重的问题.

strncpy doesn't add a terminating the '\0' character to truncated strings which causes problems like you experienced. When the string is not terminated correctly then it looks like it is longer but what you are actually seeing is the data that is placed after your buffer in memory. It can cause to serious problems.

您应该使用strlcpy而不是strncpy来正确终止字符串并返回源字符串的长度,您可以将其与缓冲区的长度进行比较以了解字符串是否被截断. strncpy返回指向缓冲区的指针的指针(由于您已经知道它,所以它不是很有用-您将其作为第一个参数传递给它),并且不会告诉您是否发生了任何截断.

Instead of strncpy you should use strlcpy which does terminate the string correctly and returns the length of the source string which you can compare to the length of your buffer to know if the string was truncated or not. strncpy returns the pointer to the pointer to your buffer (which is not very useful since you already know it - you passed it as the first argument) and doesn't tell you whether any truncation has taken place.

请参见man strlcpy:

See man strlcpy:

strlcpy()和strlcat()函数复制和连接字符串 具有与snprintf(3)相同的输入参数和输出结果.他们 旨在更安全,更一致且更不易出错 替换易于使用的函数strncpy(3)和 strncat(3). strlcpy()和strlcat()的大小为 目标缓冲区,并确保在有空间的情况下终止NUL. 请注意,dstsize中应包含NUL的空间.

The strlcpy() and strlcat() functions copy and concatenate strings with the same input parameters and output result as snprintf(3). They are designed to be safer, more consistent, and less error prone replacements for the easily misused functions strncpy(3) and strncat(3). strlcpy() and strlcat() take the full size of the destination buffer and guarantee NUL-termination if there is room. Note that room for the NUL should be included in dstsize.

在Wikipedia上

C字符串处理-替换:

and C string handling - Replacements on Wikipedia:

最流行的[a]替代品是strlcat和strlcpy函数, 它于1998年12月出现在OpenBSD 2.4中.[84]这些功能 总是将一个NUL写入目标缓冲区,从而截断结果 如有必要,并返回所需的缓冲区大小, 允许检测到截断并为 创建一个不会截断的新缓冲区.

The most popular[a] replacement are the strlcat and strlcpy functions, which appeared in OpenBSD 2.4 in December, 1998.[84] These functions always write one NUL to the destination buffer, truncating the result if necessary, and return the size of buffer that would be needed, which allows detection of the truncation and provides a size for creating a new buffer that will not truncate.

不幸的是,它未包含在glibc中-请参阅作者撰写的安全可移植性 达米安·米勒(Damien Miller)(PDF):

Unfortunately it is not included in glibc - see the Secure Portability paper by Damien Miller (PDF):

strlcpy和strlcat API会正确检查目标缓冲区的边界, 在所有情况下均以nul终止,并返回源字符串的长度, 允许检测到截断.该API已为大多数人所采用 现代操作系统和许多独立的软件包, 包括OpenBSD(起源),Sun Solaris,FreeBSD,NetBSD, Linux内核,rsync和GNOME项目.值得注意的例外 是GNU标准C库glibc [12],其维护者 坚决拒绝包含这些改进的API,并对其进行标签 尽管先前有证据表明,"BSD垃圾效率极低" [4] 在大多数情况下,它们比它们所替代的API更快[13].因此, OpenBSD端口树中存在超过100个软件包 维护自己的strlcpy和/或strlcat替代品或同等产品 API-并非理想状态.

The strlcpy and strlcat API properly check the target buffer’s bounds, nul-terminate in all cases and return the length of the source string, allowing detection of truncation. This API has been adopted by most modern operating systems and many standalone software packages, including OpenBSD (where it originated), Sun Solaris, FreeBSD, NetBSD, the Linux kernel, rsync and the GNOME project. The notable exception is the GNU standard C library, glibc [12], whose maintainer steadfastly refuses to include these improved APIs, labelling them "horribly inefficient BSD crap" [4], despite prior evidence that they are faster is most cases than the APIs they replace [13]. As a result, over 100 of the software packages present in the OpenBSD ports tree maintain their own strlcpy and/or strlcat replacements or equivalent APIs - not an ideal state of affairs.

在libbsd库中可用于Linux:

It is available for Linux in the libbsd library:

Debian和Ubuntu和其他发行版中包含软件包:

There are packages in Debian and Ubuntu and other distros:

  • https://packages.debian.org/sid/libbsd-dev
  • http://packages.ubuntu.com/search?keywords=libbsd-dev

即使您不希望依赖glibc以外的任何内容,也可以很容易地将其添加到您的项目中,因为整个源都是简短的,并且可以在许可的许可下获得:

Even if you don't want to depend on anything other than glibc it is very easy to add to your project since the entire source is short ana available under a permissive license:

/*
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>
#include <string.h>

/*
 * Copy src to string dst of size siz.  At most siz-1 characters
 * will be copied.  Always NUL terminates (unless siz == 0).
 * Returns strlen(src); if retval >= siz, truncation occurred.
 */
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
    char *d = dst;
    const char *s = src;
    size_t n = siz;

    /* Copy as many bytes as will fit */
    if (n != 0) {
        while (--n != 0) {
            if ((*d++ = *s++) == '\0')
                break;
        }
    }

    /* Not enough room in dst, add NUL and traverse rest of src */
    if (n == 0) {
        if (siz != 0)
            *d = '\0';      /* NUL-terminate dst */
        while (*s++)
            ;
    }

    return(s - src - 1);    /* count does not include NUL */
}

来源: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strlcpy.c?rev=1.11

这篇关于strncpy复制超过指定的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆