#4 __syscall_error should return long, as expected by syscall() callers

Đã đóng
%! (template.HTML=5 năm trước cách đây)đang mở bởi unixmania · 1 ý kiến

The return type of syscall() is long so __syscall_error, which is jumped to by syscall handlers to stash an error number into errno, must return long too otherwhise it returs 4294967295L instead of -1L. For example, syscall for x86_64 is defined in libc/sysdeps/linux/x86_64/syscall.S as

syscall:
    movq %rdi, %rax         /* Syscall number -> rax.  */
    movq %rsi, %rdi         /* shift arg1 - arg5.  */
    movq %rdx, %rsi
    movq %rcx, %rdx
    movq %r8, %r10
    movq %r9, %r8
    movq 8(%rsp),%r9        /* arg6 is on the stack.  */
    syscall                 /* Do the system call.  */
    cmpq $-4095, %rax       /* Check %rax for error.  */
    jae __syscall_error     /* Branch forward if it failed.  */
    ret                     /* Return to caller.  */

In libc/sysdeps/linux/x86_64/__syscall_error.c, __syscall_error is defined as

int __syscall_error(void) attribute_hidden;
int __syscall_error(void)
{
    register int err_no __asm__ ("%rcx");
    __asm__ ("mov %rax, %rcx\n\t"
             "neg %rcx");
    __set_errno(err_no);
    return -1;
}

So __syscall_error returns -1 as a 32-bit int in a 64-bit register, %rax (0x00000000ffffffff, whose decimal value is decimal 4294967295) and a test like this always returns false:

if (syscall(number, ...) == -1)
    foo();

The problem can be circumvented by the caller by coercing the returned value to int before comparing it to -1:

if ((int) syscall(number, ...) == -1)
    foo();

The same problem probably occurs on other 64-bit systems but so far only x86_64 was tested.

A pull request with an experimental test was created:

https://gogs.waldemar-brodkorb.de/oss/uclibc-ng/pulls/3

Notice that only x64_64 was tested so the chenges for other architectures mus be considered just a proposal.

The return type of syscall() is long so __syscall_error, which is jumped to by syscall handlers to stash an error number into errno, must return long too otherwhise it returs 4294967295L instead of -1L. For example, syscall for x86_64 is defined in libc/sysdeps/linux/x86_64/syscall.S as syscall: movq %rdi, %rax /* Syscall number -> rax. */ movq %rsi, %rdi /* shift arg1 - arg5. */ movq %rdx, %rsi movq %rcx, %rdx movq %r8, %r10 movq %r9, %r8 movq 8(%rsp),%r9 /* arg6 is on the stack. */ syscall /* Do the system call. */ cmpq $-4095, %rax /* Check %rax for error. */ jae __syscall_error /* Branch forward if it failed. */ ret /* Return to caller. */ In libc/sysdeps/linux/x86_64/__syscall_error.c, __syscall_error is defined as int __syscall_error(void) attribute_hidden; int __syscall_error(void) { register int err_no __asm__ ("%rcx"); __asm__ ("mov %rax, %rcx\n\t" "neg %rcx"); __set_errno(err_no); return -1; } So __syscall_error returns -1 as a 32-bit int in a 64-bit register, %rax (0x00000000ffffffff, whose decimal value is decimal 4294967295) and a test like this always returns false: if (syscall(number, ...) == -1) foo(); The problem can be circumvented by the caller by coercing the returned value to int before comparing it to -1: if ((int) syscall(number, ...) == -1) foo(); The same problem probably occurs on other 64-bit systems but so far only x86_64 was tested. A pull request with an experimental test was created: https://gogs.waldemar-brodkorb.de/oss/uclibc-ng/pulls/3 Notice that only x64_64 was tested so the chenges for other architectures mus be considered just a proposal.
unixmania đã nhận xét 5 năm trước cách đây
Poster

Moved to the mailing list.

Moved to the mailing list.
Đăng nhập để tham gia bình luận.
Không có nhãn
Không có Milestone
Không có người được phân công
1 tham gia
Đang tải...
Hủy bỏ
Lưu
Ở đây vẫn chưa có nội dung nào.