|
Visual Studio 2005 Secure Function 에 좀더 쓰겠습니다.
사실 strcpy 류의 함수를 _s 의 postfix를 붙여주는 것만으로는 충분하지 않습니다. char szBuf[10]; strcpy(szBuf, “test”) 와 같은 코드를 그냥 컴파일 하면 분명히 deprecated warning이 나옵니다. 그리고 _CRT_SECURE_NO_DEPRECATE 를 정의하거나, #pragma warning 을 이용해서 warning control을 할 수 있습니다. 이 방법은 예전의 방법입니다. Secure check를 전혀 하지 않는 방법이지요. 그런데 C++의 특성상 string manipulation 과정에서 buffer overrun이나 stack을 깨먹는 경우가 허다해서 _s postfix가 붙은 함수들이 나왔습니다. 하나만 살펴보면 errno_t strcpy_s( char *strDestination, size_t sizeInBytes, const char *strSource ); 와 같은 signature를 띄고 있습니다. 기존의 strcpy 가 2개의 parameter를 받는 반면 이 함수는 3개를 받습니다. 그래서 C/C++에서는 아래와 같이 수정해야 합니다. char szBuf[10]; strcpy_s(szBuf, 10, “test”) 그런데 사용자가 C가 아닌 C++을 사용하고 있고, _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 값이 1로 define 되어 있다면(default로 1로 정의되어 있습니다.) 있다면, template function의 도움을 받아서 좀더 쉽게 수정을 할 수가 있는데요, strcpy_s 의 template function signature는 아래와 같습니다. template <size_t size> char (&strDestination)[size], const char *strSource ); // C++ only 첫번째 parameter가 char * 가 아니라 char 배열에 대한 reference를 받는 형태로 변경되었습니다. 또한 type argument로 size_t 형태의 size를 받습니다. 이 함수를 사용하기 위해서는, 코드를 다음과 같이 바꾸어야 합니다. char szBuf[10] strcpy_s<10>(szBuf, “test”); 하지만 template function은 type inferencing 을 수행할 수 있으므로, char szBuf[10] strcpy_s(szBuf, “test”); 라고도 쓸 수 있습니다. 그래서 그냥 _s 만 쓰면 만사가 다 해결 될 것 같은데, 또 다른 문제가 있습니다. 위의 template function의 첫번째 parameter가 반드시 배열이여야 한다는 것이지요. 아래 코드를 보면 알 수 있는데요. int _tmain(int argc, _TCHAR* argv[]) { char arrayChar[10]; strcpy_s(arrayChar, "hello"); char *pDynamicChar = new char[10]; strcpy_s(pDynamicChar, "hello"); delete [] pDynamicChar; return 0; } 첫번째 strcpy_s 는 정확히 char array를 parameter로 전달됩니다. 하지만 두번째 strcpy_s 는 char *를 parameter로 전달합니다. 이 경우 template function의 type inferencing 이 일어나지 않으므로, “error C2660: 'strcpy_s' : function does not take 2 arguments” 와 같은 오류가 발생하게 됩니다. 두번째 pattern이 매우 널리 사용되는 구조임에 불구하고 말이죠. 이 경우 위의 코드는 아래와 같이 변경되어야 합니다. int _tmain(int argc, _TCHAR* argv[]) { char arrayChar[10]; strcpy_s(arrayChar, "hello"); char *pDynamicChar = new char[10]; strcpy_s(pDynamicChar, 10, "hello"); delete [] pDynamicChar; return 0; } 원래의 strcpy_s() 함수를 쓴거죠. 즉 template function 은 static array에 대해서만 동작을 합니다. 이것은 자칫 큰 혼란을 가져 올 수 있는데, 어떨때는 strcpy_s가 2개의 parameter를 가지는 것처럼 보였다가, 또 어떨때는 strcpy_s 가 반드시 3개의 parameter를 가져야 하는 것 처럼 보이기 때문입니다. 이러한 혼돈을 피하기 위해서는, 제 개인적인 견해로는 위에서 예를 들어 드린 template function은 사용하지 않는 것이 더 좋을 것 같습니다. 즉 처음부터 사용자가 _s postfix가 붙은 함수들은 모두 parameter가 한 개씩 늘었다고 이해하는 편이, 혼돈일 덜하기 때문입니다. 따라서 int _tmain(int argc, _TCHAR* argv[]) { char arrayChar[10]; strcpy_s(arrayChar, 10, "hello"); char *pDynamicChar = new char[10]; strcpy_s(pDynamicChar, 10, "hello"); delete [] pDynamicChar; return 0; } 와 같이 쓰는 것이 좀더 일관되어 보입니다. 만일 이렇게 쓰기로 결정했다면 이제 template overload function 를 원천적으로 쓰지 못하도록 막는 것이 필요합니다. 아까 말씀드린데로 _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 가 1로 정의되어 있을 때만 template overload function이 정의 되므로, 이녀석을 0로 define 해주는 것이 필요합니다. 그런데 #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 0 구문을 어디에 둘것인가도 좀 까다로운데, 가장 좋은 방법은 stdafx.h 파일에 header file include 이전에 위치시키는 것이 가장 좋겠습니다. 즉, #pragma once #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 0 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include 와 같이 쓰면 됩니다. 이런 secure Template overloads와 관련해서 3가지의 constant가 있는데요 _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 위에서 알아본 바와 같이 _s postfix가 붙은 함수 이름으로 template function을 정의합니다. 즉, errno_t strcpy_s( char (&strDestination)[size], const char *strSource ); // C++ only 를 정의하게 됩니다. _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES _s postfix가 붙지 않음 함수 이름으로 template function을 정의합니다. 즉, errno_t strcpy( char (&strDestination)[size], const char *strSource ); // C++ only 를 정의하게 됩니다. _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 를 1로 정의하게 되면 기존에 counter를 가지던 함수들 즉 strncpy 등의 함수에 대해서도 template overload function을 정의하게 됩니다. Default 값은 각각 _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1 _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 0 _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 0 입니다. 여기서 끝이 아닙니다. 또다른 문제는 return 형에 있습니다. 기존에 strcpy 류의 함수를 보면 dest string의 char *를 return 하도록 구성되어 있는데, secure function 들은 error_t 형태를 반환하게 됩니다. 다행이도 이 부분은 compiler 가 conversion 오류를 발생하기 때문에 찾기가 쉽습니다. 마지막으로 제나름의 Guideline을 알려드리면, 1. Secure function을 쓸건지 안쓸건지를 결정하자 2. Secure function을 안 쓸거라면 과감하게 _CRT_SECURE_NO_DEPRECATE 를 정의하고 프로그램이 죽어 나자빠 질때를 기다리자. 3. Secure function을 쓸거라면 _s postfix를 가진 함수로 모두 대체하고, parameter는 length가 포함된 함수를 쓰자. 4. template overload function 은 쓰지 않도록 CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 를 stdafx.h 파일에서 0 으로 정의하자. 5. 반환값을 사용하지 말자, 반환값의 형변환 오류가 발생하면 모두 변경한다. 그러나 이러한 Guideline이 모든 경우에 다 적용이 가능한 것은 아닙니다. 이미 개발되어 있는 code의 일부를 가져와서 쓰는 경우나, 어쩔 수 없이 예전의 방식을 써야 하는 경우가 아직은 상당히 존재하리라 예측됩니다. 감사합니다. Regards, 김명신 ps) 최근에 제 글을 퍼가시는 분 중에 출처를 밝히지 않고 자신의 블로그에 올려 놓은 글을 본적이 여러번 있는데요. 많이 많이 퍼가시되 출처를 꼭 기재하셨으면 합니다. 아니면 세상의 평화를 위해서 Link를 등록하는게 더 좋을지도 모르겠군요. 감사합니다.
|
![]() by 김명신 카테고리
이글루 파인더
라이프로그
이글루링크
erehwon.LAB
미친병아리가 삐약삐약 소스코드위를 걷다..... 영원히 살 것처럼 꿈을 꾸.. zoops 이야기 전기쓰레빠의 매트릭스 Junghwan and Miny.. ~★~ 우하하!!~ 프로.. [ catch me if you ca.. 블로그 옮김 -> fribirdz.. 디지털을 말한다 by oojoo 더머&채니이야기 견우의 블로그 .. 이상훈의 사는 이야기 내일은 내일의 바람이 분다. 텅빈하늘 똥강아지가 멍멍~ Atelier 기억속으로 날다(Walki.. 애자일 이야기 미친감자의 프로그래밍 .. - Last Paromix - SQL Server Troubles.. Keep going with me 최근 등록된 덧글
오~, 잘 다녀오시길,..
by 쩌비 at 11/12 와.. 몸건강히 잘다녀.. by 박중석 at 11/12 유근호 : 당연히 괜찮습.. by 김명신 at 11/06 일일이 다 세어 보셨다니.. by 유근호 at 11/04 쩌비: 그쳐? 저도 그렇게.. by 김명신 at 11/03 최근 등록된 트랙백
티맥스 윈도우 스크린샷..
by The Story of A Strang.. free7942g의 생각 by free7942g's me2DAY 프로그래머 by ego+ing 사진찍는프로그래머의 생각 by eslife's me2DAY 제프리 리처의 Windows .. by 김재호의 디지털보단 아.. 이전블로그
2009년 11월
2009년 10월 2009년 09월 2009년 07월 2009년 06월 2009년 05월 2009년 04월 2009년 03월 2009년 01월 2008년 12월 2008년 11월 2008년 10월 2008년 09월 2008년 05월 2008년 04월 2008년 03월 2007년 12월 2007년 11월 2007년 10월 2007년 09월 2007년 08월 2007년 07월 2007년 06월 2007년 05월 2007년 04월 2007년 03월 2007년 01월 2006년 12월 2006년 11월 2006년 10월 2006년 09월 2006년 08월 2006년 07월 2006년 06월 2006년 05월 2006년 04월 2006년 03월 2006년 02월 2006년 01월 2005년 12월 2005년 10월 2005년 09월 2005년 07월 2005년 06월 2005년 05월 2005년 04월 2005년 03월 2005년 02월 2005년 01월 2004년 12월 2004년 11월 2004년 10월 2004년 09월 2004년 08월 2004년 07월 2004년 06월 2004년 05월 2004년 04월 2004년 02월 2004년 01월 2003년 11월 2003년 08월 |