执行memcpy(0,0,0)是否保证安全?
我不太熟悉 C 标准,所以请耐心等待。
我想知道标准是否保证 memcpy(0,0,0)
是安全的。
我能找到的唯一限制是,如果内存区域重叠,则行为未定义......
但是我们可以认为内存区域在这里重叠吗?
I am not so well-versed in the C standard, so please bear with me.
I would like to know if it is guaranteed, by the standard, that memcpy(0,0,0)
is safe.
The only restriction I could find is that if the memory regions overlap, then the behavior is undefined...
But can we consider that the memory regions overlap here ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我有 C 标准 (ISO/IEC 9899:1999) 的草案版本,其中有一些关于该调用的有趣内容。对于初学者来说,它提到 (§7.21.1/2) 关于
memcpy
这里指出的参考指向这一点:
因此,根据 C 规范,调用
会导致未定义的行为,因为空指针被视为“无效值”。
也就是说,如果您这样做的话,如果 memcpy 的任何实际实现都崩溃了,我会感到非常惊讶,因为如果您说复制零字节,我能想到的大多数直观实现都不会执行任何操作。
I have a draft version of the C standard (ISO/IEC 9899:1999), and it has some fun things to say about that call. For starters, it mentions (§7.21.1/2) in regards to
memcpy
thatThe reference indicated here points to this:
So it looks like according to the C spec, calling
results in undefined behavior, because null pointers are considered "invalid values."
That said, I would be utterly astonished if any actual implementation of
memcpy
broke if you did this, since most of the intuitive implementations I can think of would do nothing at all if you said to copy zero bytes.只是为了好玩,gcc-4.9 的发行说明表明其优化器利用了这些规则,例如可以删除条件语句,其中
then 在
copy(0,0,0)
被调用(参见 https://gcc.gnu.org/gcc-4.9/porting_to. html)。我对 gcc-4.9 的行为有些矛盾;该行为可能符合标准,但能够调用 memmove(0,0,0) 有时是对这些标准的有用扩展。
Just for fun, the release-notes for gcc-4.9 indicate that its optimizer makes use of these rules, and for example can remove the conditional in
which then gives unexpected results when
copy(0,0,0)
is called (see https://gcc.gnu.org/gcc-4.9/porting_to.html).I am somewhat ambivalent about the gcc-4.9 behaviour; the behaviour might be standards compliant, but being able to call memmove(0,0,0) is sometimes a useful extension to those standards.
您还可以考虑 Git 2.14.x(2017 年第 3 季度)中看到的
memmove
用法,请参阅 提交 168e635(2017 年 7 月 16 日),以及提交 1773664, 提交 f331ab9, 提交 5783980(2017 年 7 月 15 日),作者: René Scharfe (
rscharfe
)。(由 Junio C Hamano --
gitster
-- 合并于 提交 32f9025,2017 年 8 月 11 日)它使用 辅助宏
MOVE_ARRAY
计算尺寸基于我们指定的元素数量并支持
NULL
当该数字为零时的指针。
原始
memmove(3)
使用NULL
调用可以导致编译器(过度急切地)优化以后的 NULL 检查。
示例:
它使用 < a href="https://github.com/git/git/blob/89c855ed3cbe64bea93ea081d0e96077e9ee8517/git-compat-util.h#L46-L59" rel="nofollow noreferrer">宏
BUILD_ASSERT_OR_ZERO
断言构建时依赖关系,作为表达式(@cond
是必须为 true 的编译时条件)。如果条件不成立,或者编译器无法计算,编译将会失败。
示例:
正如 user16217248 在 评论:
You can also consider this usage of
memmove
seen in Git 2.14.x (Q3 2017)See commit 168e635 (16 Jul 2017), and commit 1773664, commit f331ab9, commit 5783980 (15 Jul 2017) by René Scharfe (
rscharfe
).(Merged by Junio C Hamano --
gitster
-- in commit 32f9025, 11 Aug 2017)It uses an helper macro
MOVE_ARRAY
which calculates the sizebased on the specified number of elements for us and supports
NULL
pointers when that number is zero.
Raw
memmove(3)
calls withNULL
cancause the compiler to (over-eagerly) optimize out later
NULL
checks.Examples:
It uses the macro
BUILD_ASSERT_OR_ZERO
which asserts a build-time dependency, as an expression (with@cond
being the compile-time condition which must be true).The compilation will fail if the condition isn't true, or can't be evaluated by the compiler.
Example:
As noted by user16217248 in the comments:
未定义的行为可能会导致真正的问题。我刚刚遇到一个案例,确实如此。我使用 g++ 编译选项
-fsanitize=address,undefined
来找到它。就我而言,我有一个单元测试和生产代码,它们使用相同的参数调用相同的函数。单元测试通过,生产代码失败。我必须更改的代码来自 miniz-cpp。我将 mz_zip_array_push_back 函数从 更改为
,
它解决了问题。
The undefined behavior can cause real issue. I just ran into a case where it did. I used the g++ compile option
-fsanitize=address,undefined
to find it. In my case, I have a unit test and production code that are calling the same function with the same arguments. The unit test passed and the production code failed.The code I had to change is from miniz-cpp. I changed the mz_zip_array_push_back function from
to
and it resolved the issue.