unix socket错误14:EFAULT(错误地址)

时间:2012-02-13 12:59:45

标签: c sockets udp sendto

我有一个非常简单的问题,但我整个周末都找不到任何答案。我正在使用sendto()函数,它返回错误代码14:EFAULT。手册页将其描述为:

"An invalid user space address was specified for an argument."

我确信这是在谈论我指定的IP地址,但现在我怀疑它可能是它所指的消息缓冲区的内存地址 - 我找不到任何地方对此有任何澄清,任何人都可以清楚这一点吗?

谢谢, Ĵ

3 个答案:

答案 0 :(得分:26)

EFAULT如果某个参数的内存地址传递给sendto(或者更常见的是传递给任何系统调用),则会发生这种情况。可以把它想象成一个关于你的系统调用的内核域SIGSEGV。例如,如果你传递一个null或无效的缓冲区指针(用于读取,写入,发送,接收......),你就得到了

请参阅errno(3)sendto(2)等...手册页。

EFAULT根本与IP地址无关。

答案 1 :(得分:0)

带有getcpu

的最小可运行示例

为了使事情更具体,我们可以看一下getcpu系统调用,它很容易理解,并显示相同的EFAULT行为。

man getcpu中我们看到签名是:

int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);

cpu指向的内存将包含系统调用后正在运行进程的当前CPU的ID,唯一可能的错误是:

ERRORS
       EFAULT Arguments point outside the calling process's address space.

因此我们可以使用以下方法进行测试:

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>

int main(void) {
    int err, ret;
    unsigned cpu;

    /* Correct operation. */
    assert(syscall(SYS_getcpu, &cpu, NULL, NULL) == 0);
    printf("%u\n", cpu);

    /* Bad trash address == 1. */
    ret = syscall(SYS_getcpu, 1, NULL, NULL);
    err = errno;
    assert(ret == -1);
    printf("%d\n", err);
    perror("getcpu");

    return EXIT_SUCCESS;
}

编译并运行:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

样本输出:

cpu 3
errno 14
getcpu: Bad address

因此我们看到垃圾地址为1的错误调用返回了14,从内核代码https://stackoverflow.com/a/53958705/895245来看,这是EFAULT

请记住,系统调用本身会返回-14,然后syscall C包装程序会检测到由于负数导致的错误,返回-1并设置errno精确到实际的错误代码。

由于syscall非常简单,我们可以在kernel/sys.c的内核5.4实现中对此进行确认:

SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
        struct getcpu_cache __user *, unused)
{
    int err = 0;
    int cpu = raw_smp_processor_id();

    if (cpup)
        err |= put_user(cpu, cpup);
    if (nodep)
        err |= put_user(cpu_to_node(cpu), nodep);
    return err ? -EFAULT : 0;
}

因此很显然,如果-EFAULT存在问题,我们将返回put_user

值得一提的是,我的glibc在getcpu中也有一个sched.h包装器,但是在地址错误的情况下实现了段隔离,这有点令人困惑:How do I include Linux header files like linux/getcpu.h?但是这不是实际的系统调用对进程所做的,只是glibc使用该地址执行的操作。

在Ubuntu 20.04,Linux 5.4上进行了测试。

答案 2 :(得分:-1)

EFAULT是在文件“ include / uapi / asm-generic / errno-base.h”中定义的宏

#define EFAULT          14      /* Bad address */