21

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

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

我确信这是在谈论我指定的 IP 地址,但现在我怀疑它可能是它所指的消息缓冲区的内存地址 - 我在任何地方都找不到任何澄清,任何人都可以清除这个向上?

4

3 回答 3

32

EFAULT如果传递给sendto(或更一般地传递​​给任何系统调用)的某个参数的内存地址无效,则会发生这种情况。将其视为SIGSEGV与您的系统调用有关的内核领域。例如,如果您传递一个空或无效的缓冲区指针(用于读取、写入、发送、接收......),您会得到

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

EFAULT根本与IP地址无关。

于 2012-02-13T13:05:48.390 回答
2

最小的可运行示例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.

所以我们可以通过以下方式对其进行测试:

主程序

#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从内核代码中可以看出这是 EFAULT:https ://stackoverflow.com/a/53958705/895245

请记住,系统调用本身返回-14,然后syscallC 包装器检测到它是一个错误,因为它是负数,返回-1,并设置errno为实际的精确错误代码。

而且由于系统调用非常简单,我们也可以从内核 5.4 的实现中确认这一点kernel/sys.c

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,但是如果地址不正确,该实现会出现段错误,这有点令人困惑:如何包含像 linux/getcpu.h 这样的 Linux 头文件?但这不是实际的系统调用对进程所做的事情,只是 glibc 对该地址所做的事情。

在 Ubuntu 20.04、Linux 5.4 上测试。

于 2020-05-18T22:09:58.140 回答
-1

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

#define EFAULT          14      /* Bad address */
于 2018-12-28T12:33:49.587 回答