Close() x86_64 системный вызов странное возвращаемое значение - программирование
Подтвердить что ты не робот

Close() x86_64 системный вызов странное возвращаемое значение

Мой демон xinetd внезапно прекратил работу после обновления ядра (с 2.6.24 до 2.6.33). Я запустил strace и нашел это:

[...]
close(3)                                = 0
munmap(0x7f1a93b43000, 4096)            = 0
getrlimit(RLIMIT_NOFILE, {rlim_cur=8*1024, rlim_max=16*1024}) = 0
setrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0
close(3)                                = 4294967287
exit_group(1)                           = ?

В принципе, похоже, что закрытый системный вызов возвращает нечто отличное от 0 или -1

Я сделал несколько тестов, и кажется, что это происходит только с 64-битными исполняемыми файлами:

$ file closetest32
closetest32: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
$ strace closetest32
execve("./closetest32", ["closetest32"], [/* 286 vars */]) = 0
[ Process PID=4731 runs in 32 bit mode. ]
open("/proc/mounts", O_RDONLY)          = 3
close(3)                                = 0
close(3)                                = -1 EBADF (Bad file descriptor)
_exit(0)                                = ?


$ file closetest64
closetest64: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), statically linked, not stripped
$ strace closetest64
execve("./closetest64", ["closetest64"], [/* 286 vars */]) = 0
open("/proc/mounts", O_RDONLY)          = 3
close(3)                                = 0
close(3)                                = 4294967287
_exit(0)                                = ?

Я запускаю следующее ядро:

Linux foobar01 2.6.33.9-rt31.64.el5rt #1 SMP PREEMPT RT Wed May 4 10:34:12 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux

Хуже всего то, что я не могу воспроизвести ошибку на другой машине с тем же ядром.

Любые идеи?

EDIT: в соответствии с запросом: здесь код, используемый для closetest32 и closetest64

closetest32.asm:

.section .data

filename:
    .ascii "/proc/mounts"

.section .text
.globl _start
_start:
    xorl %edi, %edi
    movl $5, %eax # open() i386 system call
    leal filename, %ebx # %ebx ---> filename
    movl $0, %esi # O_RDONLY flag into esi
    int $0x80

    xorl %edi, %edi
    movl $6, %eax # close() i386 system call
    movl $3, %ebx # fd 3
    int $0x80

    xorl %edi, %edi
    movl $6, %eax # close() i386 system call
    movl $3, %ebx # fd 3
    int $0x80

    ## terminate program via _exit () system call
    movl $1, %eax # %eax =  _exit() i386 system call
    xorl %ebx, %ebx # %ebx = 0 normal program return code
    int $0x80

скомпилирован как:

as test32.asm -o test32.o --32
ld -m elf_i386 test32.o -o closetest32

closetest64.asm:

.section .data

filename:
    .ascii "/proc/mounts"

.section .text
.globl _start
_start:
    xorq %rdi, %rdi
    movq $2, %rax # open() system call
    leaq filename, %rdi # %rdi ---> filename
    movq $0, %rsi # O_RDONLY flag into rsi
    syscall

    xorq %rdi, %rdi
    movq $3, %rax # close() system call
    movq $3, %rdi # fd 3
    syscall

    xorq %rdi, %rdi
    movq $3, %rax # close() system call
    movq $3, %rdi # fd 3
    syscall

    ## terminate program via _exit () system call
    movq $60, %rax # %rax = _exit() system call
    xorq %rdi, %rdi # %rdi = 0 normal program return code
    syscall

компиляции:

as test64.asm -o test64.o
ld test64.o -o closetest64
4b9b3361

Ответ 1

Как и ожидалось, откат к предыдущей версии ядра решил проблему. Я не специалист по ядрам, но, насколько я понимаю, ответ @R.. имеет смысл:

Это 64-разрядная машина, поэтому 1 < 32-9 никогда не должно появляться. Проблема в том, что ядро ​​внутренне использует unsigned вместо int для возвращаемого значения некоторых из этих функций, а затем возвращает -EBADF, который уменьшается по модулю 2 ^ 32, а не по модулю 2 ^ 64

Проблема заключается в том, что общий код в оболочках libc syscall, который обрабатывает возвраты ошибки syscall, должен обрабатывать возвращаемое значение как длинное (поскольку он может быть указателем или длинным для некоторых системных вызовов) при сравнении, чтобы увидеть, небольшое отрицательное значение, которое указывает на ошибку. Но ядро ​​вернулось (long) (unsigned) -9, которое сильно отличается от (long) -9. или (unsigned long) -9 (любой из них работал бы).