memcpy()函数是否可重入?

5

我在信号处理程序中调用了一些C++函数,但我的程序被分段错误终止。当我使用gdb进行检查时,memcpy()函数是我收到SIGSEGV的地方。我想知道memcpy()是否是可重入函数?


看一下信号处理程序获取指针值和长度的位置。memcpy是安全的,但如果你做了类似于 free(somestruct->data); somestruct->data = 0; somestruct->len = 0; 的操作,那么当然信号可能会在这个过程中发生。 - Steve Jessop
5个回答

11

除了最高度嵌入式平台,它将是可重入的。您提到SIGSEGV,因此我假设这不是其中之一。在这种情况下,最有可能的是memcpy()不是罪魁祸首:而是调用者的问题。如果您要求memcpy()复制错误的指针(或错误的长度),那么它将是引发故障的函数。您可以轻松地这样做:

memcpy(NULL, NULL, 123456789);

这会导致SIGSEGV错误,并且它会告诉你是memcpy()引起的。当然,这并不是memcpy的错误 - 它只是在执行你告诉它要做的事情。你的信号处理程序正在使用一些奇怪的东西调用它。通过回溯(在gdb或任何你拥有的工具中),可以找到调用者的位置。如果失败了,就打印出你传递给memcpy的参数。


2
Posix规定不能从信号处理程序中调用memcpy。实际上,它可能会起作用。至少大部分时间是这样的。但这并不是完全有保障的。 - James Kanze
1
@James:我想检查的方法是用明显的循环替换memcpy的调用,看看是否仍会出现段错误。如果问题消失了,那么memcpy就不是异步信号安全的。如果问题仍然存在,那么问题要么在于实际复制之外,要么涉及到char访问不是信号原子性的微妙问题。 - Steve Jessop
1
@James 这太令人惊讶了。我找不到任何关于memcpy()不安全的信号(即使是从opengroup中)。在某些微控制器/DSP架构上,它由于其本地变量具有静态位置而不可重入,但是我无法想象如何在其他架构上使其不安全,除非您非常努力地尝试。你有链接吗? - John Ripley
1
@James 实际上,我现在明白了:“异步安全”函数。但那是一些系统调用的 POSIX 函数列表,而不是基本的 C 库函数。按照那种解释,即使调用“strcmp”或“isdigit”也是不安全的。 - John Ripley
4
正如你所说,异步信号安全函数列表只提到了新的Posix函数,而没有涉及标准C函数。Posix在某个地方指出,任何未被声明为异步信号安全的函数,不必保证是异步信号安全的。C标准表示,通常情况下不能从信号处理程序中调用库函数(7.1.4/4)。因此,除非标准明确指出可以调用 memcpy,否则我们只能依靠对实现可能性的直觉。我们知道这不是错误,但据我所知,这并非由Posix保证,glibc可能会提供保证。 - Steve Jessop

2
以下是翻译的结果:

关于(不)可重入函数和信号处理程序(与GNU C库相关的部分),可以在此处找到一些相关信息:

以下部分特别与您的问题相关:

  • "仅从内存对象中读取是安全的,前提是您能够处理可能在信号可以交付时出现在对象中的任何值。请记住,对某些数据类型的赋值需要多个指令,这意味着如果其类型不是原子的,则处理程序可能在变量的赋值“中间”运行。"

  • "仅向内存对象写入是安全的,只要在处理程序可能运行的任何时间更改值不会干扰任何内容。"


1

我不明白为什么它不能是可重入的。我不确定,但我认为这很大程度上取决于你使用的库。


0

除非memcpy实现得很糟糕,否则它是可重入的。它只能使用你提供的指针和长度值。所有参数都是按值传递的,因此一旦函数被激活,这些值将不会在其堆栈帧上更改,无论信号和/或其他线程如何。


0

我认为问题在于您将无效(或已删除)指针作为memcpy函数的参数,请仔细检查您的代码。

此致敬礼。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接