为什么这种故意错误地使用 strcpy 不会严重失败?

发布于 2024-11-30 19:39:46 字数 1034 浏览 2 评论 0原文

为什么下面使用 strcpy 的 C 代码对我来说效果很好?我尝试通过两种方式使其失败:

1)我尝试将 strcpy 从字符串文字转移到分配的内存中,但分配的内存太小而无法容纳它。它复制了整个事情并且没有抱怨。

2) 我尝试从一个非 NUL 终止的数组中调用 strcpystrcpyprintf 工作得很好。我原以为 strcpy 会复制 char 直到找到 NUL,但什么也没有出现,它仍然停止了。

为什么这些都不会失败?我只是在某种程度上“幸运”,还是我误解了这个功能的工作原理?它是特定于我的平台(OS X Lion)的,还是大多数现代平台都以这种方式工作?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char *src1 = "123456789";
    char *dst1 = (char *)malloc( 5 );

    char src2[5] = {'h','e','l','l','o'};
    char *dst2 = (char *)malloc( 6 );

    printf("src1: %s\n", src1);
    strcpy(dst1, src1);
    printf("dst1: %s\n", dst1);
    strcpy(dst2, src2);
    printf("src2: %s\n", src2);
    dst2[5] = '\0';
    printf("dst2: %s\n", dst2);

    return 0;
}

运行此代码的输出是:

$ ./a.out   
src1: 123456789
dst1: 123456789
src2: hello 
dst2: hello

Why does the below C code using strcpy work just fine for me? I tried to make it fail in two ways:

1) I tried strcpy from a string literal into allocated memory that was too small to contain it. It copied the whole thing and didn't complain.

2) I tried strcpy from an array that was not NUL-terminated. The strcpy and the printf worked just fine. I had thought that strcpy copied chars until a NUL was found, but none was present and it still stopped.

Why don't these fail? Am I just getting "lucky" in some way, or am I misunderstanding how this function works? Is it specific to my platform (OS X Lion), or do most modern platforms work this way?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char *src1 = "123456789";
    char *dst1 = (char *)malloc( 5 );

    char src2[5] = {'h','e','l','l','o'};
    char *dst2 = (char *)malloc( 6 );

    printf("src1: %s\n", src1);
    strcpy(dst1, src1);
    printf("dst1: %s\n", dst1);
    strcpy(dst2, src2);
    printf("src2: %s\n", src2);
    dst2[5] = '\0';
    printf("dst2: %s\n", dst2);

    return 0;
}

The output from running this code is:

$ ./a.out   
src1: 123456789
dst1: 123456789
src2: hello 
dst2: hello

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

濫情▎り 2024-12-07 19:39:46

首先,复制到太小的数组中:

C 对于超出数组边界没有保护,因此如果 dst1[5..9] 处没有任何敏感内容,然后你很幸运,副本进入了你不合法拥有的内存,但它也不会崩溃。但是,该内存并不安全,因为它尚未分配给您的变量。另一个变量很可能会分配给它的内存,然后覆盖您放入其中的数据,从而稍后损坏您的字符串。

其次,从非空终止的数组中进行复制:

尽管我们通常被告知内存中充满了任意数据,但其中很大一部分会被清零。即使没有在src2中放置空终止符,src[5]很可能恰好是\ 0 无论如何。这样就可以复制成功了。请注意,这是保证的,并且可能在任何时间、任何平台上的任何运行中失败。但这次你很幸运(可能是大多数时候),而且它奏效了。

First, copying into an array that is too small:

C has no protection for going past array bounds, so if there is nothing sensitive at dst1[5..9], then you get lucky, and the copy goes into memory that you don't rightfully own, but it doesn't crash either. However, that memory is not safe, because it has not been allocated to your variable. Another variable may well have that memory allocated to it, and later overwrite the data you put in there, corrupting your string later on.

Secondly, copying from an array that is not null-terminated:

Even though we're usually taught that memory is full of arbitrary data, huge chunks of it are zero'd out. Even though you didn't put a null-terminator in src2, chances are good that src[5] happens to be \0 anyway. This makes the copy succeed. Note that this is NOT guaranteed, and could fail on any run, on any platform, at anytime. But you got lucky this time (and probably most of the time), and it worked.

执手闯天涯 2024-12-07 19:39:46

超出分配内存范围的覆盖会导致未定义的行为
所以在某种程度上,是的,你很幸运。

未定义的行为意味着任何事情都可能发生,并且该行为无法解释,因为定义语言规则的标准没有定义任何行为。

编辑:
再想一想,我想说你真的不幸,程序运行良好并且没有崩溃。现在有效并不意味着它永远有效,事实上,它是一颗滴答作响的炸弹。

根据墨菲定律
任何可能出错的事情都会出错[“而且很可能是在最不方便的时刻”< code>]

[ ] - 是我对法律的编辑:)

Overwriting beyond the bounds of allocated memory causes Undefined Behavior.
So in a way yes you got lucky.

Undefined behavior means anything can happen and the behavior cannot be explained as the Standard, which defines the rules of the language, does not define any behavior.

EDIT:
On Second thoughts, I would say you are really Unlucky here that the program works fine and does not crash. It works now does not mean it will work always, In fact it is a bomb ticking to blow off.

As per Murphy's Law:
"Anything that can go wrong will go wrong"["and most likely at the most inconvenient possible moment"]

[ ]- Is my edit to the Law :)

昨迟人 2024-12-07 19:39:46

是的,你只是很幸运。

通常,堆是连续的。这意味着当您写入经过malloc的内存时,可能会损坏后续内存块或用户内存块之间可能存在的某些内部数据结构。这种损坏通常在有问题的代码出现很久之后才显现出来,这使得调试此类错误变得困难。

您可能会收到 NUL ,因为内存恰好是零填充的(无法保证)。

Yes, you're quite simply getting lucky.

Typically, the heap is contiguous. This means that when you write past the malloced memory, you could be corrupting the following memory block, or some internal data structures that may exist between user memory blocks. Such corruption often manifests itself long after the offending code, which makes debugging this type of bugs difficult.

You're probably getting the NULs because the memory happens to be zero-filled (which isn't guaranteed).

你又不是我 2024-12-07 19:39:46

正如@Als 所说,这是未定义的行为。这可能会崩溃,但不一定

许多内存管理器分配较大的内存块,然后以较小的块(可能是 4 或 8 字节的倍数)将其交给“用户”。因此,您在边界上的写入可能只是写入分配的额外字节。或者它会覆盖您拥有的其他变量之一。

As @Als said, this is undefined behaviour. This may crash, but it doesn't have to.

Many memory managers allocate in larger chunks of memory and then hand it to the "user" in smaller chunks, probably a mutliple of 4 or 8 bytes. So your write over the boundary probably simply writes into the extra bytes allocated. Or it overwrites one of the other variables you have.

朮生 2024-12-07 19:39:46

你没有malloc-ing足够的字节。第一个字符串 "123456789" 为 10 个字节(存在空终止符),并且 {'h','e','l','l','o'} 是 6 个字节(再次为空终止符腾出空间)。您当前正在使用该代码破坏内存,这会导致未定义(即奇怪)的行为。

You're not malloc-ing enough bytes there. The first string, "123456789" is 10 bytes (the null terminator is present), and {'h','e','l','l','o'} is 6 bytes (again, making room for the null terminator). You're currently clobbering the memory with that code, which leads to undefined (i.e. odd) behavior.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文