java集合能复制集合吗_开始在复制功能中发现的错误集合

java集合能复制集合吗

memcpy

I've already noticed a few times before that programmers seem to tend to make mistakes in simple copy functions. Writing a profound article on this topic is going to take quite a while since I'll have to do some thorough research and sample collecting, but for now I'd like to share a couple of examples I stumbled upon recently.

我已经注意到几次,程序员似乎倾向于在简单的复制函数中犯错误。 由于我将不得不做一些彻底的研究和样本收集,因此需要花费相当长的时间写一篇深刻的文章,但是现在,我想分享一些我偶然发现的例子。

Baader-Meinhof现象? 我不这么认为 (The Baader-Meinhof phenomenon? I don't think so)

As a member of the PVS-Studio team, I come across numerous bugs found with our tool in various projects. And as a DevRel, I love telling people about that :). Today I'm going to talk about incorrectly implemented copy functions.

作为PVS-Studio团队的一员,我遇到了在各个项目中使用我们的工具发现的许多错误。 作为DevRel,我喜欢告诉人们:)。 今天,我将讨论错误实现的复制功能。

I saw such functions before, but I never wrote them down as I didn't think they were worth mentioning. But since I discovered the tendency, I can't but start collecting them. For a start, I'm going to show you two recently found specimens.

我以前看过这样的函数,但是我从未写下来它们,因为我认为它们不值得一提。 但是,由于我发现了这种趋势,所以我不得不开始收集它们。 首先,我将向您展示两个最近发现的标本。

You may argue that two cases don't make a tendency yet; that I paid attention solely because they occurred too close in time and the Baader-Meinhof phenomenon kicked in.

您可能会争辩说,两种情况还没有形成趋势。 我之所以关注是因为它们发生得太近并且Baader-Meinhof现象开始了。

The Baader-Meinhof phenomenon, also called Frequency Illusion, is a cognitive bias where a person stumbles upon a piece of information and soon afterwards encounters the same subject again, which makes them believe this subject appears exceptionally frequently. Baader-Meinhof现象,也称为频率错觉,是一种认知偏见,人们偶然发现一条信息,不久之后又再次遇到同一主题,这使他们相信该主题异常频繁地出现。

I don't think that's the case. I already had a similar experience with poorly written comparison functions, and my observation was later proved by real examples: "The Evil within the Comparison Functions".

我认为并非如此。 我已经有比较糟糕的比较函数编写经验,后来我的观察得到了真实示例的证实:“ 比较函数中的邪恶 ”。

Okay, let's get to the point. That introduction was a bit too long for a brief note on two examples :).

好吧,让我们说清楚。 对于两个示例的简短说明,该介绍太长了:)。

例子1 (Example 1)

In the article about the check of the Zephyr RTOS, I mentioned a failed attempt to make a function that should work like strdup:

在有关Zephyr RTOS检查的文章中 ,我提到了使功能类似于strdup的尝试失败:

static char *mntpt_prepare(char *mntpt)
{
  char *cpy_mntpt;

  cpy_mntpt = k_malloc(strlen(mntpt) + 1);
  if (cpy_mntpt) {
    ((u8_t *)mntpt)[strlen(mntpt)] = '\0';
    memcpy(cpy_mntpt, mntpt, strlen(mntpt));
  }
  return cpy_mntpt;
}

PVS-Studio diagnostic message: V575 [CWE-628] The 'memcpy' function doesn't copy the whole string. Use 'strcpy / strcpy_s' function to preserve terminal null. shell.c 427

PVS-Studio诊断消息: V575 [CWE-628]'memcpy'函数不会复制整个字符串。 使用'strcpy / strcpy_s'函数保留终端null。 shell.c 427

The analyzer says the memcpy function copies the string but fails to copy the terminating null character, which is a very strange behavior. You may think the copying of the terminating null takes place in the following line:

分析器说memcpy函数复制字符串,但是无法复制终止的空字符,这是非常奇怪的行为。 您可能认为终止空值的复制发生在以下行中:

((u8_t *)mntpt)[strlen(mntpt)] = '\0';

But that's wrong – this is a typo that causes the terminating null to get copied into itself. Notice that the target array is mntpt, not cpy_mntpt. As a result, the mntpt_prepare function returns a non-terminated string.

但这是错误的–这是一种错字,会导致终止null被复制到自身中。 注意,目标数组是mntpt ,而不是cpy_mntpt 。 结果, mntpt_prepare函数返回一个非终止的字符串。

This is what the code was actually meant to look like:

这就是代码的实际含义:

((u8_t *)cpy_mntpt)[strlen(mntpt)] = '\0';

I don't see any reason, though, for implementing this function in such a complicated and unconventional way. Because of this overcomplicating, what should have been a small and simple function ended up with a critical bug in it. This code can be reduced to the following:

不过,我看不出有任何理由以如此复杂和非常规的方式实现此功能。 由于这种复杂性,本来应该是一个小而简单的功能却最终导致了一个严重的错误。 此代码可以简化为以下代码:

static char *mntpt_prepare(char *mntpt)
{
  char *cpy_mntpt;

  cpy_mntpt = k_malloc(strlen(mntpt) + 1);
  if (cpy_mntpt) {
    strcpy(cpy_mntpt, mntpt);
  }
  return cpy_mntpt;
}

例子2 (Example 2)

void myMemCpy(void *dest, void *src, size_t n) 
{ 
   char *csrc = (char *)src; 
   char *cdest = (char *)dest; 
   for (int i=0; i<n; i++) 
     cdest[i] = csrc[i]; 
}

We didn't catch this one; I came across it on StackOverflow: C and static Code analysis: Is this safer than memcpy?

我们没有抓住这个。 我在StackOverflow上碰到了它: C和静态代码分析:这比memcpy安全吗?

Well, if you check this function with PVS-Studio, it will expectedly issue the following warnings:

好吧,如果您使用PVS-Studio选中此功能,则预期会发出以下警告:

  • V104 Implicit conversion of 'i' to memsize type in an arithmetic expression: i < n test.cpp 26

    V104在算术表达式中将 “ i”隐式转换为memsize类型:i <n test.cpp 26

  • V108 Incorrect index type: cdest[not a memsize-type]. Use memsize type instead. test.cpp 27

    V108错误的索引类型:cdest [不是内存大小类型]。 请改用memsize类型。 test.cpp 27

  • V108 Incorrect index type: csrc[not a memsize-type]. Use memsize type instead. test.cpp 27

    V108错误的索引类型:csrc [不是memsize-type]。 请改用memsize类型。 test.cpp 27

Indeed, this code has a flaw, and it was pointed out in the replies on StackOverflow. You can't use a variable of type int as an index. In a 64-bit program, an int variable would most certainly (we don't talk about exotic architectures now) be 32 bits long and the function would be able to copy only as much as INT_MAX bytes, i.e. not more than 2 GB.

确实,此代码有缺陷,并且在StackOverflow的答复中已指出。 您不能将int类型的变量用作索引。 在64位程序中,一个int变量很可能肯定是32位长(我们现在不谈论奇异的体系结构),并且该函数只能复制多达INT_MAX个字节,即不超过2 GB。

With a larger buffer to copy, a signed integer overflow will occur, which is undefined behavior in C and C++. By the way, don't try to guess how exactly the bug would manifest itself. Surprisingly, it's quite a complicated topic, which is elaborated on in the article "Undefined behavior is closer than you think".

使用较大的缓冲区进行复制时,将发生有符号整数溢出,这在C和C ++中是未定义的行为。 顺便说一句,不要试图猜测错误将如何准确地表现出来。 令人惊讶的是,这是一个相当复杂的主题,在文章“ 未定义的行为比您认为的更紧密 ”中进行了详细说明。

The funniest thing is that the code shown above was written in an attempt to eliminate some warning of the Checkmarx analyzer triggered by a call of the memcpy function. The wisest thing the programmer could come up with was to reinvent the wheel. But the resulting copy function – however simple – ended up flawed. The programmer probably made the things even worse than they had already been. Rather than try and find the cause of the warning, he or she chose to conceal the issue by writing their own function (thus confusing the analyzer). Besides, they made a mistake of using an int variable as a counter. And yes, code like that may not be optimizable. Using a custom function instead of the existing efficient and optimized function memcpy is not an efficient decision. Don't do that :)

最有趣的是,上面显示的代码旨在消除因调用memcpy函数而触发的Checkmarx分析器的某些警告。 程序员能想到的最明智的事情就是重新发明轮子。 但是最终的复制功能(无论多么简单)最终都存在缺陷。 程序员可能使事情变得比以前更糟。 他或她没有尝试查找警告的原因,而是选择通过编写自己的功能来隐藏问题(从而使分析仪感到困惑)。 此外,他们错误地使用了一个int变量作为计数器。 是的,这样的代码可能不会被优化。 使用自定义函数代替现有的高效和优化函数memcpy并不是一个有效的决定。 不要那样做:)

结论 (Conclusion)

Well, it's only the start of the journey, and it might well take me a few years before I collect enough examples to write a profound article on this topic. Actually, it's only now that I'm starting to keep an eye for such cases. Thanks for reading, and be sure to try PVS-Studio on your C/C++/C#/Java code – you may find something interesting.

好吧,这仅仅是旅程的开始,可能我要花几年的时间才能收集足够的示例来撰写有关该主题的深刻文章。 实际上,直到现在我才开始关注这种情况。 感谢您的阅读,并确保在C / C ++ / C#/ Java代码上尝试使用PVS-Studio –您可能会发现一些有趣的东西。

翻译自: https://habr.com/en/company/pvs-studio/blog/495640/

java集合能复制集合吗

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值