我有一个非常简单的问题,但整个周末我都没有找到任何答案。我正在使用该sendto()
函数,它返回错误代码 14:EFAULT。手册页将其描述为:
"An invalid user space address was specified for an argument."
我确信这是在谈论我指定的 IP 地址,但现在我怀疑它可能是它所指的消息缓冲区的内存地址 - 我在任何地方都找不到任何澄清,任何人都可以清除这个向上?
最小的可运行示例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
,然后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;
}
很清楚,如果.-EFAULT
有问题,我们会看到返回put_user
值得一提的是,我的 glibc 中也有一个getcpu
包装器sched.h
,但是如果地址不正确,该实现会出现段错误,这有点令人困惑:如何包含像 linux/getcpu.h 这样的 Linux 头文件?但这不是实际的系统调用对进程所做的事情,只是 glibc 对该地址所做的事情。
在 Ubuntu 20.04、Linux 5.4 上测试。
EFAULT 是在文件“include/uapi/asm-generic/errno-base.h”中定义的宏
#define EFAULT 14 /* Bad address */