(C)추억

7949 단어 valgrindmemorycmalloc

메모리 관리의 위험
C 언어를 부정하는 데 사용된 논거 중 수동 메모리 관리에 관한 논거는 의심할 여지없이 10위권 안에 든다.
일반적으로 다음과 같습니다.
  • 오류 발생 가능성
  • 보안 취약성 발생
  • , 결국 지구 온난화!
  • 지금 그들 중 일부는 약간 분노하지만 대다수는 틀림없다.C에서 동적 메모리를 사용하는 것은 반드시 정확하게 처리해야 하는 일이다.
    주요 원인은 메모리와 관련된 버그를 추적하고 복구하기 어렵다는 것이다.오류의 근본 원인은 오류가 발생한 줄 이외의 줄과 파일일 수 있습니다.
    더 심각한 것은 어떤 실수가 다른 상황에서가 아니라 어떤 상황에서 발생할 수도 있다는 것이다.한 기계에 있지만 다른 기계에 있는 게 아니에요...정말 악몽이다!
    우리는 가장 흔히 볼 수 있는 오류에 대해 몇 가지 대책을 찾아야 한다.
  • 더 이상 사용하지 않는 메모리(메모리 누출)
  • 참조 초기화되지 않은 메모리
  • 해제된 메모리 참조
  • 할당된 메모리의 끝에 쓰기 (버퍼 넘침).
  • 우리가 뭘 할 수 있는지 보여줘!

    쓰레기 수집
    대부분의 현대 프로그래밍 언어 (Java, Python, Go) 는 스팸 수집기를 사용합니다. 메모리를 인용하지 않고 재분배할 수 있는 시스템을 추적합니다.1970년대 이래로 Lisp와 Basic에서 쓰레기 수집 기능을 사용했는데 그 자체가 현대적인 기능이 아니라는 것을 주의해 주십시오.
    스팸 수집기(GC라고도 부른다)는 매우 유용하지만 조심하지 않으면 GC가 사용되지 않은 메모리를 식별하기 위해 실행을 중지할 때 의외의 행동을 초래할 수 있다.Rust는 시스템 프로그래밍 언어가 되기 위한 것이지만 GC를 전혀 사용하지 않는다. 이것은 우연이 아니다.
    C에 있어서 가장 좋은 선택은 Boehm-Demers-Weiser conservative Garbage Collector일 것이다. 이것은 매우 성숙하고 많은 플랫폼에 적용된다.
    나는 나의 환경 청결 업무를 다른 사람에게 맡기고 싶지 않지만, 어떤 경우에는 GC를 사용하는 것이 가장 적합한 방법이다.

    와르그린
    메모리 오류를 추적하는 최종 무기는 Valgrind입니다. 디버깅과 응용 프로그램을 분석하는 데 사용되는 도구입니다.그 중 하나인 memcheck을 사용하면 메모리 유출, 버퍼 넘침 등을 쉽게 식별할 수 있습니다.그것은 정말 너의 하루를 구할 수 있다!
    그러나 단점도 있습니다.
  • 컴파일할 때 모든 디버깅 정보를 포함해야 합니다. (대부분의 컴파일러는 -g)
  • 을 최적화할 필요가 없습니다.
  • 은 코드가 CPU가 아닌 Valgrind에서 재해석되기 때문에 매우 느릴 수 있습니다(20 또는 30배 느릴 수 있습니다).
  • Linux 및 MacOS(기타 일부 Unix 플랫폼)에만 적용
  • 이것은 복잡한 도구여서 약간의 시간이 걸려야만 장악할 수 있다
    복잡한 응용 프로그램이 있다면 오랜만에 동료가 계승했을 수도 있다는 뜻이다. Valgrind는 응용 프로그램을 분석하고 메모리 문제를 확인하는 데 가장 좋은 선택이다.아직 해보지 않았다면

    추적 기억 장치
    자주 발생하는 상황은 GC나Valgrind와 같은 소프트웨어 도구보다 필요한 도구가 훨씬 적다는 것이다.메모리 사용 상황을 추적하는 데 도움을 줄 수 있는 것들만 필요할 수도 있다.
    적어도 이런 상황은 나에게 자주 발생한다. 이것이 바로 내가 표준의malloc(),free() 등을 바꾸기 위해 함수를 한 조 작성한 이유이다.stderr에 그들이 무엇을 하고 있는지 적어라.
    이런 방법으로 나는 다음과 같은 검사를 할 수 있다.
    잘못된 포인터
  • 이중 자유 블록
  • 버퍼 넘침
  • 메모리 누출
  • 나는 Valgrind를 떠나서 나중에 내가 그렇게 많은 기억 문제를 발견하지 못할 것이라고 확신할 수 있다.
    당신은 Github에서 memchk을 찾을 수 있습니다. 이것은 가장 작은 실현입니다. 제가 어떻게 하는지 보십시오.

    사용법memchk을 사용하려면 다음을 수행해야 합니다.
  • 은memchk를 포함한다.h제목
  • 정의된 기호 MEMCHK를 사용하여
  • 컴파일
  • 에 memchk를 추가합니다.c 당신측에 보내는 소식 출처
  • 코드를 변경할 필요가 없습니다 (제목 포함 제외)!
    모든 것이 정상적이라고 확신할 때, 정의되지 않은 MEMCHK를 사용하여 다시 컴파일하고 표준 함수를 사용할 수 있습니다.
    새 함수 memchk () 는 유효한 포인터가 아니면 오류를 가지고 프로그램을 종료합니다.
    매우 기본적인 예 mtest1.c:
     1: #include <stdio.h>
     2: #include <stdlib.h>
     3: #include "memchk.h"
     4:
     5: int main(int argc, char *argv[])
     6: {
     7:   char *s;
     8:
     9:   s = malloc(10);
    10:   // s[10] = '\0'; // Buffer overflow!
    11:   free(s);
    12: }
    
    컴파일하고 실행하면 메모리 사용에 대한 모든 정보가 포함된 로그가 생성됩니다.
    > gcc -O2 -c memchk.c
    > gcc -O2 -c -DMEMCHK mtest1.c
    > gcc -o m1 mtest1.o memchk.o
    > ./m1.c
    malloc(10) mtest1.c:9
     -> 0x5634ea39a2b0 +10 -0 mtest1.c:9
    free(0x5634ea39a2b0) mtest1.c:11
    MEMCHK: 0x5634ea39a2b0 mtest1.c:11
     -- OK mtest1.c:11
     -> (nil) +0 -10 mtest1.c:11
    
    10행에 주석이 없으면 결과는 달라집니다.
    malloc(10) mtest1.c:9
     -> 0x55ed8b0222b0 +10 -0 mtest1.c:9
    free(0x55ed8b0222b0) mtest1.c:11
    MEMCHK: 0x55ed8b0222b0 mtest1.c:11
     -- KO: BUFFER OVERRUN mtest1.c:11
    Aborted
    
    보시다시피 블록 경계가 넘어간 사실이 검출되었습니다.
    오류가 발견되면 즉시 중단하고 프로그램에서 오류가 전파되는 것은 무의미하다.
    메모리 유출을 검출하는 것은 매우 쉽다.간단한 프로그램(또는 스크립트)을 작성하여 ->으로 시작하는 줄을 선택하고 +x-y을 추가할 수 있습니다.만약 마지막에 0을 얻지 못한다면 메모리를 방출하는 것을 잊어버려라.동시에, 너는 네가 사용하고 있는 메모리의 양도 기록할 수 있다.

    엔진 덮개
    비결은 간단하다.새로운 기능으로 관리되는 블록은 요청된 블록보다 크고, 할당된 블록의 시작과 끝에는 두 개의 초병이 배치되어 유효성과 버퍼 넘침을 검사합니다.
        ┏━━━━━━━━━━━━━━┓  ◄── Actually allocated memory
        ┃  0xCA5ABA5E  ┃  ◄── Sentinel to identify valid blocks
        ┣━━━━━━━━━━━━━━┫
        ┃              ┃  ◄── Block size
        ┣━━━━━━━━━━━━━━┫  ◄── Returned pointer
        ┃              ┃
        ~              ~
        ┃              ┃
        ┣━━━━━━━━━━━━━━┫
        ┃  0x10CCADD1  ┃  ◄── Sentinel to identify overflow
        ┗━━━━━━━━━━━━━━┛
    
    

    미주
    이런 방법은 결코 완벽하지 않다. 그것은 단지 가장 흔히 볼 수 있는 상황만을 포괄한다.예를 들어 end sentinel을 삭제하지 않는 경우 버퍼 넘침을 초래할 수 있지만 버퍼 넘침은 한 메모리 블록에서 다른 메모리 블록으로 순서대로 복사될 때 발생하기 때문에 sentinel을 삭제하는 것이 가장 흔히 볼 수 있는 상황이다.
    또한 오류가 발생한 위치(10번째 줄)를 정확하게 가리키지는 않았지만 최소한 오류가 무시되지는 않았다.MEMCHK를 정의하지 않은 상태에서 모든 내용을 다시 컴파일하면 정상적으로 실행될 수 있는 좋은 프로그램이 있습니다.적어도 생산 중에 심각한 문제가 발생하기 전에!

    결론
    메모리 관리는 엄숙한 문제다.쓰레기 수집기를 사용하기로 결정하든지, 혼자서 모든 일을 완성하든지, 쓰레기 수집기가 정확하게 완성될 수 있도록 최선을 다해야 한다.
    다행히도, 우리는 여러 가지 선택과 도구로 우리의 일을 완성할 수 있다.기억 문제에 대해서는 안 돼!

    사후 스크립트
    어떤 사람이 나에게 C11 표준(부록 K에서)은 하나의 기능(_s으로 끝난다)을 정의했는데 이것은 전통적인 대응 기능보다 더욱 안전하다는 것을 일깨워 주었다.C17 및 C2x 표준 파일 초안에도 동일한 부록이 있습니다.예를 들어 strcpy_s()은 메모리 경계를 넘지 않습니다.
    비록 이것은 사실이지만, 컴파일러가 이 함수들에 대한 지원도 선택할 수 있다.ccc(v9.30)와clang(v10.0)은 모두 그것을 실현하지 못했다(당신은 그것들이 정의하지 않은 __STDC_LIB_EXT1__을 통해 판단할 수 있다). 그리고 머지않아 그것들도 실현하지 못할 것 같다.
    지난번에 내가 검사했을 때 Microsoft cl(v19.29)도 첨부파일 K를 완전히 실현하지 못했다. 첨부파일이 존재하는 원인은 Microsoft가 컴파일러에 도입한'_s'함수 때문이다.
    따라서 내가 얼마나 표준을 따르기를 좋아하는지 말하자면, 우리는 첨부 파일 K가 우리의 메모리 관리가 건전하고 깨끗하다는 것을 확보하는 데 도움을 줄 것이라고 기대할 수 없을 것 같다. (

    좋은 웹페이지 즐겨찾기