반응형

strcpy_s등의 _s 류의 문자열처리 함수에 대해

 

VC++ 6.0으로 작성된 프로젝트를 VS 2005 이상으로 변환해서 컴파일 하거나,
VS2005
로 프로젝트 작성시 strcpy, sprintf, strcat 등의 C 런타임 함수를 사용하면 다음과 같은 warning 메시지를 접하게 된다
.

warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

strcpy_s, sprintf_s, strcat_s
와 같은 안전한 스트링 함수를 사용하라는 내용인데
...
이 함수들의 원형을 살펴보면 두번째 인자가 캐릭터의 숫자임을 알 수 있다
.
< 밑에 GrooveFella이 지적해주신대로 sizeof(buffer)가 아니라 _countof(buffer)로 계산해야 한다. >

errno_t strcpy_s( char *strDestination, size_t numberOfElements, const char *strSource );

strDestination 버퍼를 넘어서는 메모리 복사를 방지하는 스트링 함수라 이해하면 되겠다.
그래서 _s(afe)로 추측되는 함수들을 만들어 놨을 테고
...

그럼 이 보기 싫은 warnig을 어떻게 처리할 것인가
?
1.
제일 무식한 방법으로는 아래의 pragma를 설정하여, 해당 warnig을 표시하지 않도록 설정한다
.
  #pragma warning(disable: 4996)
2.
그게 아니면 당연히 _s류의 함수로 바꿔야 겠지?
여기서 한가지 집고 넘어가자면

char szBuf[MAX_PATH];
strcpy_s( szBuf, "aaa" );

형태의 코딩이 가능하다는 거다.

char *pszBuf = new char[MAX_PATH];
strcpy_s( pszBuf, "aaa");

이러한 코딩은 error C2660: 'strcpy_s' : 함수는2개의매개변수를사용하지않습니다.”라는 컴파일 에러가 발생한다.

두 코드의 차이점이 보이는가?
그렇다. _s류 함수의 첫번째 인자로 배열이 들어가면, 매크로에 의해 사이즈가 자동으로 계산된다.


3.
... 그럼 조금 더 생각해 보자.
strcpy_s
strncpy와 무엇이 다를까? 아니면 똑같이 동작하는가
?
아래의 코드를 돌려보면 답은 명확해 진다.

char *pszBuf = new char[6];
strncpy( pszBuf,
"aaaaaaaa", 7 ); // --> (1)
strcpy_s( pszBuf, 7,
"aaaaaaa"); // --> (2)

(1) 의 코드는 할당된 메모리(6byte)를 넘어서서 7byte까지 'a'로 채운 후 다음 코드가 진행된다.
(
머 이후의 상황이야 엄한 곳에서 메모리를 할당하거나 해제 할 때 문제가 발생 할 테지, 운이 억수로

나쁘다면 문제가 없는 것처럼 보일 수 도 있을 테고...)
(2)
의 코드는 메모리 에러를 발생시키며, 프로그램이 종료된다
.

귀찮다고 방치하지 말고, 이 기회에 바꿔보는 건 어떨까?

 

 

반응형
반응형

대학교때, 시험문제에 "오버로드와 오버라이드의 차이점을 기술하라"는 문제가 나왔던것이 아직도 기억난다.
한줄의 답도 적지 못했던 기억도
...

워낙 공부를 등한시한 터라, 오버로드라고는 스타크래프트의 저그 밥통(?) 외에는 떠오르는게  없었다
.

경력 6년 차인 지금이라면 답을 적을 수 있을까
?
.. 확신이 안선다
.

두가지가 의미하는 정의는 알고 있지만, 단어와 정의가 항상 매치가 안된다
.

해서. 이 글을 쓰며 머리속에 각인시키려 한다.

·        오버로드(Overload)
함수(메소드) 이름은 같고 인자 갯수나 타입이 다른 함수를 정의하는 것을 의미한다.
(
리턴값만을 달리하는 오버로드는 작성 할 수 없다)

int OverloadFuncAdd( int x, int y );
double OverlaodFuncAdd( double x, double y);

OverloadFuncAdd() 함수가 오버로드된 것이다

·        오버라이드(Override)
상위 클래스의 매소드를 재정의 하는 것이다.
메소드 이름은 물론 인자 갯수나 타입도 동일해야 하며, 주로 상위 클래스의 동작을 상속받은 하위클래스에서 메소드의 동작을 변경하기 위해 사용된다.

class BaseClass
{
protected:
    virtual int OverrideFuncAdd( int x, int
y);
};

class SubClass : public
BaseClass
{
    int OverrideFuncAdd( int x, int
y);
}

와 같은 형태로 사용된다



명확하게 기억하자.

 

반응형
반응형

Warning C4748: /GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function


checked
빌드로 열심히 빌드해서 테스트 중이었다.
같은 코드구만 free빌드로 컴파일을 시도했더니 발생한 에러다
.
동일한 코드를 쓰는 다른 프로젝트는 잘만 빌드 되는 구만
...

차이점을 찾다 보니
,
디버깅할때 로컬 변수 정보가 제대로 표시되지 않아 설정했던 다음 구문이 문제였다.

#pragma optimize("", off)


해결 방법은 optimize option을 켜던가, 아니면 문제가 발생하는 함수를

#pragma optimize("", on)
func()
{
}
#pragma optimize("", off)

로 감싸주면 된다.

에러의 내용은 아래를 참조.


 



http://msdn.microsoft.com/ko-kr/library/ms235398(VS.80).aspx


컴파일러 경고(수준 3) C4748

오류 메시지

함수에서 최적화를 사용하지 않으므로 /GS를 지정해도 로컬 버퍼 오버런에서 매개 변수 및 지역 변수를 보호할 수 없습니다.
/GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function

기본적으로 활성화되어 있는 /GS(버퍼 보안 검사)는 함수의 최적화 기능을 사용하지 않는 한 함수의 매개 변수와 지역 변수에서 로컬 버퍼 오버런이 발생하지 않도록 보호할 수 없습니다.

함수에 jmp 또는 jcc와 같은 흐름 제어 문이 포함된 인라인 어셈블리 코드가 있는 경우 컴파일러는 최적화를 비활성화합니다.

이 경고를 해결하고 /GS를 사용하여 로컬 버퍼 오버런에서 매개 변수와 지역 변수를 보호하려면 최적화를 활성화해야 합니다.

예제

다음 샘플에서는 C4748 경고가 발생하는 경우를 보여 줍니다.

// C4748.cpp
// compile with: /O2 /W3
#include <string.h>
#include <stdlib.h>

#pragma optimize("", off)
void f(const char *str) {  // C4748 warning
   char buf[100];
   strcpy_s(buf, _countof(buf), str);
}
#pragma optimize("", on)

int main() {
   f("aa");
}
반응형

'C++' 카테고리의 다른 글

std::vector  (0) 2009.08.26
strcpy_s등의 _s 류의 문자열 처리함수  (4) 2009.04.01
오버로드/오버라이드  (2) 2009.04.01
Name Mangling(Name Decoration)  (0) 2008.10.07
메모리 에러  (0) 2008.03.25
반응형

Name Mangling

프로그램에서 함수를 선언하거나 전역 변수 등을 선언 했을 때, 실제 생성되는 함수는 컴파일 단계에서 일정한 규칙을 가지고 변경되는데, 이를 네임 맹글링(Name Mangling)혹은 네임 데커레에션(Name Decoration)이라 부른다.

이러한 작업은 Linker가 다른 Scope에 있는 같은 이름의 함수와 변수에 대해 구별할 수 있도록 하는 요소이므로, Compiler 입장에서는 중요한 작업이다.


일반적으로 Compiler 는 함수에 대해서 그 함수의
이름과 함수의 파라미터 타입 그리고 Calling Convention등을 사용하여 그 이름을 만들어 내게 된다
.

이러한 네임 맹글링은 컴파일러 마다 다른 규칙을 가지게 된다
.

외부라이브러리를 링크하여 컴파일 할때 선언부만 포함하고 실 라이브러리를 포함하지 않으면 발생하는 에러에서 간혹 보게 되는
?TestFunc1@@YAXHPAH@Z와 같은 형태의 함수이름이 네임 맹글링된 함수의 이름이다
.

* C++
로 작성되는 프로그램에서 함수 앞에 붙이는 extern "C" 선언은 함수를 컴파일 할 때, 네임 맹글링을 하지 않고 함수이름만으로 네이밍 하도록 한다(즉 C type으로 함수명을 네이밍하게 된다).

아래의 예에서 extern "C"를 기술했을 경우와, 그렇지 않은 경우의 차이를 확인 할 수 있다.

 

 extern "C" __declspec(dllexport) void TestFunc( int x);

 

__declspec(dllexport) void TestFunc( int x);



* "UNDNAME" 유틸리티를 이용하여 네임 맹글링된 함수의 선언을 확인 할 수도 있다.

(이 유틸리티는 Visual Studio 설치폴더 C:\Program Files\Microsoft Visual Studio x.x\VC\bin 에서 찾을 수 있으며, 파일로 첨부한다.)

 

위에서 생성된 함수를 UNDNAME.exe를 이용해 데코레이션을 제거하면 예상대로 아래와 같이 표시된다.


 

* 이러한 이유 때문에 정적으로 링크하여 사용할 것이 아니라면
   - 즉,
   - LoadLibrary(), GetProcAddress()의 절차를 통해 함수포인터를 얻어 사용하거나,
   - 다른 언어로 작성된 Application에서 Dll을 로드하여 사용
할 용도의 Dll이라면 export되는 함수에 대해 함수의 export선언부에 
extern "C"를 붙여주거나 .def파일을 이용해서 네임맹글링이 적용되지 않도록 하여야 한다.

 

반응형
반응형

C/C++로 작성한 어플리케이션에서 발생하는 에러중 가장 골치 아픈 에러가 메모리 에러가 아닌가 싶다.( 물론 deadlock이라던가 이런 문제들도 간단친 않지만... )

보통 몇년간 프로그래밍을 하다보면 malloc 혹은 free()를 호출할때(당연히 new/delete도 마찬가지다) 쌩뚱맞게도 메모리 에러가 발생하는 케이스를 경험하게 된다
.

처음 이 에러를 접했을때는 '대략난감'이랄까
?
하지만 대부분은 '내 잘못'인 에러 케이스다
.

이 현상의 대부분은 malloc을 통해 할당받은 메모리의 범위를 넘어서서 데이터를 복사하거나, 이중으로 free를 호출할때 발생한다.

(이 문제는 Windows의 메모리 관리 방법과 밀접한 관계가 있으며, 상기 동작으로 인해 Memory Block의 정보를 담고 있는 Description(?) 영역을 Overwirte해서 발생할 수 있다.- 그림과 함께 좀더 상세한 내용을 기술 하고 싶지만, 아직 내공이 부족해서 ㅡ.: 머지 않은 미래에 Study해서 Posting해보려 한다)

예를 들어.

char *p = (char *)malloc(10);
memcpy( p, p2, 11);

char *p = (char *)malloc(10);
free
(p);
.
.
.
free(p);

< * free한 메모리에 대해 NULL을 할당하는 것도 좋은 코딩 습관이다. NULL 포인터에 대한 free연산은 적법(?)하다>


이런 경우 코드가 포함되어 있다면, 불특정한 순간에 malloc하거나 free 할때 메모리 에러로 인해 어플이 종료되거나 드라이버의 경우 BSOD를 만나게 된다.
(
물론 위와 같이 눈에 띄게 코딩되어 있진 않을꺼라 장담한다 ㅡㅡ
)

운이 좋다면 문제 발생 지점의 전후를 살펴보면 문제를 확인 할 수도 있겠지만
,
세상일이 어디 그리 만만 하던가
?

1. Applicaton Verifier
gflags를 통해 도움을 받거나,

2. 문제가 발생한 메모리 블록을 추적해서 문제 지점을 유추하거나
3.
그것 마저 여의치 않다면 할당, 해제, 할당한 메모리에 대해 복사하는 코드들에 대한 꼼꼼한 체크가 필요하다.

 

반응형

+ Recent posts