programing

함수에서 구조체를 반환할 때 GCC 버그가 발생할 수 있습니다.

goodsources 2022. 8. 31. 22:53
반응형

함수에서 구조체를 반환할 때 GCC 버그가 발생할 수 있습니다.

O'Neill의 PCG PRNG를 구현하던 중 GCC에서 버그를 발견한 것 같습니다.(Godbolt의 컴파일러 탐색기의 초기 코드)

곱셈 후oldstate타고MULTIPLIER(rdi에 저장된 결과), GCC는 이 결과를 에 추가하지 않습니다.INCREMENT, 무브INCREMENT대신 rdx로 이동합니다.이 값은 rand32_ret.state의 반환값으로 사용됩니다.

재현 가능한 최소한의 예(Compiler Explorer):

#include <stdint.h>

struct retstruct {
    uint32_t a;
    uint64_t b;
};

struct retstruct fn(uint64_t input)
{
    struct retstruct ret;

    ret.a = 0;
    ret.b = input * 11111111111 + 111111111111;

    return ret;
}

생성된 어셈블리(GCC 9.2, x86_64, -O3):

fn:
  movabs rdx, 11111111111     # multiplier constant (doesn't fit in imm32)
  xor eax, eax                # ret.a = 0
  imul rdi, rdx
  movabs rdx, 111111111111    # add constant; one more 1 than multiplier
     # missing   add rdx, rdi   # ret.b=... that we get with clang or older gcc
  ret
# returns RDX:RAX = constant 111111111111 : 0
# independent of input RDI, and not using the imul result it just computed

흥미롭게도 uint64_t를 첫 번째 멤버로 하도록 구조를 수정하면 두 멤버를 uint64_t로 변경하는 것과 마찬가지로 올바른 코드가 생성됩니다.

x86-64 System V는 RDX:RAX에서 16바이트 미만의 구조를 반환합니다(복사 가능한 경우).이 경우 두 번째 멤버는 RDX에 있습니다.이는 RAX의 상단이 정렬용 패딩이기 때문입니다..b언제.a폭이 좁은 타입입니다.(sizeof(retstruct)어느 쪽이든 16입니다.__attribute__((packed))따라서 alignof(uint64_t) = 8을 존중한다.

이 코드에는 GCC가 "잘못된" 어셈블리를 내보낼 수 있는 정의되지 않은 동작이 포함되어 있습니까?

그렇지 않으면 https://gcc.gnu.org/bugzilla/에 보고됩니다.

여기에는 UB가 없습니다.여러분의 타입은 서명되지 않았기 때문에 서명된 오버플로우 UB는 불가능하고 이상할 것이 없습니다.(서명되어도 오버플로우 UB를 발생시키지 않는 입력에 대해서는 올바른 출력을 생성해야 합니다.rdi=1)는, GCC의 C++ 프론트 엔드에서도 고장났습니다.

또한 GCC8.2는 AArch64RISC-V에 대해 올바르게 컴파일합니다.madd사용 후 지시movk또는 RISC-V mul을 생성하여 상수를 로드한 후 추가합니다.)만약 GCC가 UB를 찾고 있다면, 우리는 일반적으로 그것을 찾고 적어도 비슷한 타입의 폭과 레지스터 폭을 가진 다른 ISA에서도 코드를 해독할 것으로 예상합니다.

Clang도 올바르게 컴파일합니다.

이는 GCC 5에서 6으로 회귀한 것으로 보입니다. GCC 5.4 컴파일은 올바르고 6.1 이상 컴파일은 그렇지 않습니다(Godbolt).

질문의 MCVE를 사용하여 GCC의 bugzilla에 보고할 수 있습니다.

x86-64 System V structure-return handling의 버그인 것 같습니다.아마 패딩을 포함한 구조일 것입니다.인라이닝할 때, 그리고 확대했을 때 왜 효과가 있는지 설명이 됩니다.a 패딩uint64_t(패딩 패딩)로 합니다.

은 것이 this this this this this this this this로 수정되었습니다.trunk/master.

여기 관련 커밋이 있습니다.

그리고 이것은 문제를 해결하기 위한 패치입니다.

「」에해, 「」를 참조해 .reload_combine_recognize_pattern함수가 USE insns를 조정하려고 했습니다.

이 코드에는 GCC가 "잘못된" 어셈블리를 내보낼 수 있는 정의되지 않은 동작이 포함되어 있습니까?

질문에서 제시된 코드의 동작은 C99 및 이후의 C 언어 표준에 관해 잘 정의되어 있습니다.특히 C는 함수가 제한 없이 구조값을 반환하는 것을 허용한다.

언급URL : https://stackoverflow.com/questions/59871171/possible-gcc-bug-when-returning-struct-from-a-function

반응형