컴파일 타임에 delete []와 delete의 오용 탐지


19

delete컴파일 타임에 아래에 주석 처리 된 오류 를 감지 할 수 있는지 알고 싶습니다 . 특히 g ++ 컴파일러에 대해 듣고 싶습니다.

ClassTypeA *abc_ptr = new ClassTypeA[100];  
abc_ptr[10].data_ = 1;  
delete abc_ptr; // error, should be delete []  

7
어쨌든 수동으로 delete를 호출해서는 안됩니다.
Martin York

9
@LokiAstari 댓글이 도움이되었다고 생각하셨습니까?
James

5
@ 제임스 : 예. 열쇠는 "수동으로"입니다.
Martin York

때로는이를 준수하기 위해 많은 레거시 코드를 다시 작성해야합니다.
Nick Keighley

사용 std::unique_ptr<ClassTypeA[]>하면 필요하지 않습니다.
user253751

답변:


6

일반적으로 컴파일러는 이러한 오류를 감지 할 수 없습니다. 예 : 일부 클래스의 생성자 new TypeName[]가을 사용 하여 일부 데이터 멤버를 할당 하지만 소멸자가 delete대신을 잘못 사용 한다고 가정합니다 delete[]. 생성자와 소멸자가 별도의 컴파일 단위로 정의 된 경우, 소멸자를 정의하는 파일을 컴파일 할 때 컴파일러가 생성자를 정의하는 별도로 컴파일 된 파일의 사용법과 일치하지 않음을 어떻게 알 수 있습니까?

GNU 컴파일러와 관련해서는 그렇지 않습니다. 위에서 언급했듯이 일반적인 경우에는 그렇게 할 수 없습니다. 컴파일러는 정의되지 않은 동작이므로 일치하지 않는 새로운 / 삭제 오류를 감지하지 않아도됩니다. UB는 컴파일러 공급 업체의 "감옥 탈옥"카드입니다.

valgrind와 같은 도구는 이러한 종류의 새로운 / 삭제 불일치를 감지 할 수 있지만 런타임에는 그렇게합니다. 실행 파일을 만들기 위해 결국 컴파일 될 모든 소스 파일을 확인하는 정적 분석 도구가있을 수 있지만 이러한 종류의 오류를 감지하는 정적 분석 도구는 없습니다.


필자는 이 특정 시나리오에 대한 규칙이있는 Parasoft 라는 정적 분석 도구를 사용했습니다 . 특정 프로젝트의 모든 파일에서 올바르게 실행됩니다 (정확하게 구성된 경우). 그러나 킬리안 포스의 대답에 대한 Pete Kirkham의 의견과 같은 시나리오를 얼마나 잘 처리하는지 확실하지 않습니다.
Velociraptors

28

적절한 RAII 클래스를 사용할 수 있습니다 delete. 이것이 유일하게 안전한 방법이며,이 오류는 당신이 delete직접 부를 수있는 매우 많은 것 중 하나 일뿐 입니다.

항상 클래스를 사용하여 동적 평생 리소스를 관리하면 유형 시스템이 올바른 리소스 파괴를 시행합니다.

편집 : "코드를 감사하고 변경할 수 없으면 어떻게합니까?" 당신은 망했어.


18
실제로 질문에 대답하지 않기
메이슨 휠러

2
불일치를 감지하는 유일한 방법은 RAII 클래스를 사용하는 유형 시스템을 사용하는 것입니다.
DeadMG

9
... 그건 말이 안됩니다. RAII 클래스 (런타임 메커니즘)의 사용은 컴파일러가 컴파일 타임에 알고있는 정적 유형 시스템 정보와 어떤 관련이 있습니까?
메이슨 휠러

6
@MasonWheeler는 boost :: shared_ptr 및 boost :: shared_array를 예로 들어 봅니다. shared_ptr을 제거하면 객체가 삭제되고 shared_array는 배열을 삭제합니다. shared_ptr을 shared_ptr에 할당 할 수 없으므로 배열을 사용하여 shared_ptr을 구성하지 않는 한 유형 시스템은 잘못된 삭제가 사용되는 것을 방지합니다.
피트 Kirkham

4
일반적으로 이와 같은 대답은 도움이되는 것보다 더 불쾌합니다. 그러나이 경우 실제로 적용됩니다. 그는 일반적인 오류에 대한 컴파일러 시행을 찾고 있으며 RAII를 올바르게 사용하면 이러한 유형의 오류를 방지하여 원하는 것을 정확하게 얻을 수 있습니다. +1
riwalk

10

이 특정 오류-예. 이런 종류 의 오류는 일반적으로 안타깝게도 아닙니다! 실제로 실행하지 않고 실행 흐름을 예측하는 것은 임의의 프로그램에서는 불가능합니다. (따라서 대부분의 컴파일러는 예제와 같은 간단한 사례를 탐지하지조차 않습니다.)

따라서 DeadMG의 대답은 적절한 것입니다.주의를 기울여 올바르게 시도하지 마십시오. 인간의 관심은 잘못입니다. 언어 제공 수단을 사용하고 컴퓨터에주의를 기울이십시오.


이를 위해서는 실행 흐름을 어떻게 예측해야합니까? 이것은 나에게 완전히 정적 인 컴파일 타임 지식처럼 보입니다. 컴파일러의 타입 시스템은 배열이 무엇인지 아닌지 알고 있습니다.
메이슨 휠러

캐스트가 있더라도? 죄송합니다. 잘못 입력하면 답변을 삭제하겠습니다.
Kilian Foth

12
@MasonWheeler abc_ptr의 정적 유형은 ClassTypeA*새로운 if ( rand() % 2 == 1 ) abc_ptr = new ClassTypeA;유형 과 삭제 사이에 선을 삽입 할 수 있기 때문에 정적 유형 시스템의 Nothing abc_ptr은 배열 또는 동적 객체를 가리키는 지 또는 다른 객체 또는 배열을 가리키는 지 여부를 보여줍니다 .
피트 Kirkham

아, 맞아 저는 실제 배열 유형의 언어로 작업하는 데 익숙해 져서 C-land에서 어떻게 망쳐 놓았는지 잊어 버렸습니다. :(
Mason Wheeler

1
@Pete Kirkham, @Mason Wheeler : 그러나 여전히 런타임은에서 가리키는 주소에 얼마나 많은 객체가 저장되어 있는지 확인해야합니다 abc_ptr. 그렇지 않으면 어떻게 적절한 양의 메모리를 할당 해제 할 수 있습니까? 따라서 런타임은 할당 해제해야하는 오브젝트 수를 알고 있습니다.
조르지오

4

객체의 인스턴스화와 소멸이 동일한 범위에 있기 때문에 컴파일시 사소한 경우를 감지 할 수 있습니다. 일반적으로 삭제는 인스턴스화와 동일한 범위 또는 동일한 소스 파일에 없습니다. 그리고 C ++ 포인터의 타입은 할당 방식은 물론, 타입의 단일 객체를 참조하는지 또는 배열을 참조하는지에 대한 정보를 전달하지 않습니다. 따라서 일반적으로 컴파일 타임에이를 진단 할 수 없습니다.

가능한 특별한 경우를 진단하지 않겠습니까?

C ++에는 범위에 연결된 동적 리소스, 즉 스마트 포인터 및 상위 수준 배열 ( std::vector) 과 관련된 유출을 처리하기위한 도구가 이미 있습니다 .

올바른 delete맛 을 사용하더라도 코드는 여전히 예외 안전하지 않습니다. new[]와 코드 사이의 코드 delete[]가 동적 엑시트에 의해 종료되면 삭제는 실행되지 않습니다.

런타임 감지가 진행되는 Valgrind한이 도구는 런타임에서이를 감지하는 데 효과적입니다. 손목 시계:

==26781== Command: ./a.out
==26781==
==26781== Mismatched free() / delete / delete []
==26781==    at 0x402ACFC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048498: main (in /home/kaz/test/a.out)
==26781==  Address 0x4324028 is 0 bytes inside a block of size 80 alloc'd
==26781==    at 0x402B454: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==26781==    by 0x8048488: main (in /home/kaz/test/a.out)

물론 Valgrind가 모든 플랫폼에서 실행되는 것은 아니며 도구에서 모든 런타임 상황을 재현하는 것이 항상 실용적이거나 가능한 것은 아닙니다.


이 사소한 경우는 컴파일 타임에 감지 할 수 있다고 말합니다. 이를 달성하기 위해 어떤 컴파일 명령을 사용하는지 말씀해 주시겠습니까?
SebGR

"컴파일 시간에 감지 될 수있다"는 의미는 g ++에없는 것이 아니라 컴파일러에서 구현하기 쉽다는 것을 의미합니다. 컴파일러는 해당 범위를 처리 할 때 식별자의 전체 수명을 파악하고 구문에 연결된 의미 적 속성으로 할당 정보를 전파 할 수 있습니다.
Kaz

-3

컴파일 타임 / 정적 분석 시간에 감지하는 몇 가지 간단한 예 :

RHEL7 호스트에서 cppcheck 1.77 and 1.49

> cat test.cc
#include <memory>
int main(){char* buf = new char[10];delete buf;}

http://cppcheck.sourceforge.net/

> cppcheck -x c++ test.cc
Checking test.cc ...
[test.cc:2]: (error) Mismatching allocation and deallocation: buf

clang++ 3.7.1RHEL7 과 함께

> clang++ --analyze -x c++ test.cc
test.cc:2:37: warning: Memory allocated by 'new[]' should be deallocated by
'delete[]', not 'delete'
int main(){char* buf = new char[10];delete buf;}
                                    ^~~~~~~~~~
1 warning generated.

Clang Static Analyzer는 std::unique_ptr통과하지 못한 경우도 감지 할 수 있습니다<char[]>

> cat test2.cc
#include <memory>
int main(){std::unique_ptr<char> buf(new char[10]);}

https://clang-analyzer.llvm.org/

> clang++ --analyze -x c++ -std=c++11 test2.cc
In file included from test2.cc:1:
In file included from /opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/memory:81:
/opt/rh/devtoolset-4/root/usr/lib/gcc/x86_64-redhat-linux/5.3.1/
../../../../include/c++/5.3.1/bits/unique_ptr.h:76:2: 
warning: Memory allocated by
      'new[]' should be deallocated by 'delete[]', not 'delete'
        delete __ptr;
        ^~~~~~~~~~~~
1 warning generated.

이것을 clang, 테스트 및 내가 찾은 버그에 추가 한 작업에 대한 링크로 아래를 업데이트하십시오.

이것은 reviews.llvm.org/D4661- "일치하지 않는 '신규'와 '삭제'사용을 감지 하여 clang에 추가되었습니다 .

테스트는 테스트 / 분석 / 미스 매치 된 Deallocator-checker-test.mm에 있습니다.

이 열린 버그를 발견했습니다-bugs.llvm.org/show_bug.cgi?id=24819


정적의 검출 분석기 찾을 수 없음 - 하나 의심 하나의 특정 잘못된 사용을 대신 발견 한 모든 잘못된 용도 (희망 실수 없이 잘 용도)
Caleth
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.