programing

memcpy(0,0,0)를 실행해도 안전한가?

bestcode 2022. 8. 27. 09:36
반응형

memcpy(0,0,0)를 실행해도 안전한가?

저는 C기준에 대해 잘 모르니 조금만 참아주세요.

표준으로 보증하고 있는지 알고 싶다.memcpy(0,0,0)안전합니다.

내가 찾을 수 있는 유일한 제한은 기억 영역이 겹치면, 그 동작은 정의되지 않는다는 것이다.

하지만 메모리 영역이 여기서 겹친다고 생각해도 될까요?

C 규격의 초안 버전(ISO/IEC 9899:1999)을 가지고 있습니다만, 그 콜에 대해서 재미있는 것이 몇 가지 있습니다.우선, (77.21.1/2)에 대해 언급하고 있다.memcpy그거

인수가 다음과 같이 선언된 경우size_tn은 함수의 배열 길이를 지정합니다.n은 해당 함수에 대한 호출 값 0을 지정할 수 있습니다.이 하위 절의 특정 함수에 대한 설명에서 달리 명시되지 않는 한, 그러한 호출에 대한 포인터 인수는 7.1.4에서 기술된 바와 같이 여전히 유효한 값을 가져야 합니다.이러한 콜에서는, 문자를 검출하는 함수는 오카렌스를 검출하지 않고, 2개의 문자 시퀀스를 비교하는 함수는 제로, 문자를 카피하는 함수는 제로입니다.

여기서 나타내는 참조는, 다음을 나타내고 있습니다.

함수에 대한 인수에 잘못된 값(함수의 도메인 외부의 값, 프로그램의 주소 공간 외부의 포인터, 대응하는 파라미터가 일정하지 않은 경우 늘 포인터 또는 수정 불가능한 저장소로 가는 포인터 등) 또는 변수 번호가 o인 함수에 의해 예상되지 않는 유형(승격 후)이 있는 경우f 인수, 동작은 정의되어 있지 않습니다.

그래서 C사양에 따르면, 전화하는 것처럼 보입니다.

memcpy(0, 0, 0)

null 포인터가 "확장값"으로 간주되기 때문에 정의되지 않은 동작이 발생합니다.

그렇긴 하지만, 만약 실제 이행을 한다면 나는 완전히 놀랄 것이다.memcpy이렇게 하면 문제가 생깁니다.직관적인 구현의 대부분은 제로바이트를 복사하라고 해도 전혀 효과가 없기 때문입니다.

재미삼아 gcc-4.9의 릴리스 노트는 최적기가 이러한 규칙을 사용하고 있음을 나타내고 있습니다.예를 들어, gcc-4.9의 조건부여기에서 조건을 삭제할 수 있습니다.

int copy (int* dest, int* src, size_t nbytes) {
    memmove (dest, src, nbytes);
    if (src != NULL)
        return *src;
    return 0;
}

그러면 예상치 못한 결과를 얻을 수 있습니다.copy(0,0,0)가 호출됩니다(https://gcc.gnu.org/gcc-4.9/porting_to.html) 참조).

저는 gcc-4.9 동작에 대해 다소 애매모호합니다.동작은 표준에 준거할 수 있지만 memmove(0,0,0)를 호출할 수 있는 것은 때때로 이러한 표준에 대한 유용한 확장입니다.

또, 다음의 사용법을 고려할 수도 있습니다.memmoveGit 2.14.x (2017년 3분기)에서 확인

168e635(2017년 7월 16일)를 참조하고 1773664, f331ab9, 5783980(2017년 7월 15일)을 르네 샤프()rscharfe에 의해 커밋합니다.
(2017년 8월 11일 Junio C Hamano에 의해 병합---- 커밋 32f9025에서)

지정된 수의 요소에 따라 크기를 계산하고 지원하는 도우미 매크로를 사용합니다.NULL포인터를 지정합니다.
미가공 콜NULL컴파일러가 나중에 최적화(과잉)될 수 있습니다.NULL체크합니다.

MOVE_ARRAY 에는 중복될 가능성이 있는 어레이 엔트리의 범위를 이동하기 위한 안전하고 편리한 도우미가 추가되었습니다.
요소의 크기를 유추하고, 바이트 단위로 크기를 얻기 위해 자동으로 안전하게 곱하고, 요소의 크기를 비교함으로써 기본적인 유형의 안전 점검을 수행합니다.memmove(3)서포트NULL포인터 iff 0 요소를 이동합니다.

#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
    BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
static inline void move_array(void *dst, const void *src, size_t n, size_t size)
{
    if (n)
        memmove(dst, src, st_mult(size, n));
}

:

- memmove(dst, src, (n) * sizeof(*dst));
+ MOVE_ARRAY(dst, src, n);

빌드 타임 의존성을 주장하는 매크로를 표현식으로 사용합니다.@cond참말
조건이 참이 아니거나 컴파일러가 평가할 수 없는 경우 컴파일은 실패합니다.

#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)

예:

#define foo_to_char(foo)                \
     ((char *)(foo)                     \
      + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))

아요 no요 。memcpy(0,0,0)는 그하지 않을 입니다.표준 라이브러리는 그 콜에 실패하지 않을 것입니다.단, 테스트 환경에서는 버퍼 오버런 및 기타 문제를 검출하기 위해 memcpy()에 추가 코드가 존재할 수 있습니다.그리고 그 특별한 버전의 memcpy()가 NULL 포인터에 어떻게 반응하는지는 미정의입니다.

언급URL : https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0

반응형