【问题标题】:unix socket error 14: EFAULT (bad address)unix 套接字错误 14:EFAULT(错误地址)
【发布时间】:2012-03-04 21:06:27
【问题描述】:

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

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

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

【问题讨论】:

  • 您提供给 sendmsg 的 const struct msghdr *message 参数中的某些内容无效,如果您需要有关更多细节的帮助,请发布一些相关代码。

标签: c sockets udp sendto


【解决方案1】:

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

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

EFAULT 与 IP 地址完全无关。

【讨论】:

  • 嗯,好的,谢谢,我回家后会检查缓冲区指针,看看是否能解决问题!
  • 是的,做到了!我把我的一些指针弄糊涂了,谢谢!
【解决方案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.

所以我们可以测试一下:

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

请记住,系统调用本身返回-14,然后syscall C 包装器检测到由于为负数而导致错误,返回-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;
}

很清楚,如果put_user 有问题,我们会返回-EFAULT

值得一提的是,我的 glibc 在 sched.h 中也有一个 getcpu 包装器,但是在地址错误的情况下,该实现会出现段错误,这有点令人困惑:How do I include Linux header files like linux/getcpu.h? 但实际情况并非如此syscall 对进程所做的事情,就像 glibc 对该地址所做的事情一样。

在 Ubuntu 20.04、Linux 5.4 上测试。

【讨论】:

    【解决方案3】:

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

    #define EFAULT          14      /* Bad address */
    

    【讨论】:

      猜你喜欢
      • 2021-01-24
      • 2015-08-26
      • 2013-07-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-28
      • 1970-01-01
      • 2015-05-26
      • 1970-01-01
      相关资源
      最近更新 更多