hyeonk lab

블로그 이미지

hyeonk

hello world! hyeonk lab.

안전한 문자열 함수들

c & c++ 2013. 5. 3. 10:14

안전한 문자열 함수들

2006-07-13 신영진

C언어 표준에 포함된 문자열 함수들 중에 일부는 매우 위험하다. 대표적인 함수가 strcpy와 sprintf함수다. 이 두 함수의 경우 출력 값으로 문자열 포인터를 전송한다. 하지만 출력 문자열 포인터의 크기를 입력 받지 않기 때문에 버퍼 오버런의 위험을 가지고 있다. 버퍼 오버런의 경우 보안상 취약점이 될 수 있다. 따라서 견고한 프로그램을 작성하기 위해서는 되도록 이 함수들을 사용하지 않는 것이 좋다.

버퍼 오버런

버퍼 오버런이란 프로그램 내부에서 사용하는 메모리 공간을 프로그래머가 기존에 의도했던 것을 넘어서서 덮어 쓰는 것을 말한다. 스택 공간을 침범하는 것을 스택 오버런, 힙 공간을 침범하는 것을 힙 오버런이라 한다. 아래 코드는 어떻게 스택 오버런이 발생하는 지 보여준다.

view plaincopy to clipboardprint?
  1. TCHAR *src = TEXT("123456789");
  2. TCHAR dest[5];
  3. _tcscpy(dest, src);

위의 코드를 살펴보면 dest는 최대 4글자를 저장할 수 있다. 왜냐하면 C언어의 경우 끝을 알리기 위해서 NULL 종료 문자를 사용하기 때문이다. 하지만 실제로 복사를 하고자 하는 소스 문자열은 4글자보다 큰 문자다. 따라서 프로그래머가 잡아둔 메모리 공간을 침범해서 덮어쓰게 된다. 이렇게 될 경우 스택이 깨지고 코드가 엉뚱한 곳으로 리턴되는 결과를 만들 수 있다.

Windows에서는 이러한 보안상 취약한 함수들을 대체할 새로운 안전한 함수들을 작성해서 Platform SDK를 통해서 배포하고 있다. 이 함수들은 strsafe.h에 들어있다. 우선 간략하게 어떠한 함수들이 들어 있는지 살펴보도록 하자.

기존함수 대체 함수
strcpy StringCbCopy, StringCbCopyEx
StringCchCopy, StringCchCopyEx
strncpy StringCbCopyN, StringCbCopyNEx
StringCchCopyN, StringCchCopyNEx
strcat StringCbCat, StringCbCatEx
StringCchCat, StringCchCatEx
strncat StringCbCatN, StringCbCatNEx
StringCchCatN, StringCchCatNEx
sprintf StringCbPrintf, StringCbPrintfEx
StringCchPrintf, StringCchPrintfEx
vsprintf StringCbVPrintf, StringCbVPrintfEx
StringCchVPrintf, StringCchVPrintfEx
gets StringCbGets, StringCbGetsEx
StringCchGets, StringCchGetsEx
strlen StringCbLength
StringCchLength

함수 이름이 규칙적으로 지어진 덕분에 함수의 종류를 한눈에 파악할 수 있다. 전체적으로 을 네 가지 종류의 함수가 있다. Cb, Cch계열과 일반 함수와 Ex 함수가 그것이다. Cb계열의 함수는 버퍼 크기를 인자로 받는다. 즉, 버퍼가 몇 바이트 크기를 가지느냐 하는 것을 기준으로 삼는다. 반면에 Cch계열 함수들은 버퍼의 길이를 인자로 받는다. 몇 글자를 저장할 수 있느냐 하는 것을 기준으로 삼는다. Ex 함수는 일반 함수의 기능에 버퍼의 잘림과 패딩을 다루는 추가적인 기능을 가진 함수들이다.

일반 함수의 경우 표준 함수와 동일한 인자를 받도록 되어 있다. 단지 추가적으로 버퍼의 크기를 하나 더 받는다. 따라서 여기서는 StringCbCopy와 StringCchPrintf의 사용법만 살펴보도록 하겠다. 다른 함수들의 자세한 사용방법을 알고 싶다면 MSDN을 참고하도록 하자.

view plaincopy to clipboardprint?
  1. HRESULT StringCbCopy(
  2. LPTSTR pszDest,
  3. size_t cbDest,
  4. LPCTSTR pszSrc
  5. );

StringCbCopy 함수의 원형이다. 이 함수는 strcpy와 동일한 기능을 한다. pszDest에는 복사될 버퍼 포인터를, cbDest에는 pszDest의 크기를, 그리고 pszSrc에는 복사할 문자열 포인터를 넣어주면 된다. cbDest를 제외하면 strcpy와 동일한 의미의 인자가 순서대로 입력된다는 것을 알 수 있다. 결과 값은 함수의 성공 여부다. 성공한 경우 S_OK를 리턴 한다. 위에 나열된 모든 String계열 함수의 리턴 값은 HRESULT다. COM에 사용되는 것과 동일한 타입이기 때문에 FAILED, SUCCEEDED매크로를 사용하면 손쉽게 에러 여부를 체크할 수 있다. StringCbCopy함수를 사용해 간단한 문자열을 복사하는 과정은 아래와 같다.

view plaincopy to clipboardprint?
  1. TCHAR dest[6];
  2. TCHAR *src = "Hello World!";
  3. if(FAILED(StringCbCopy(dest, sizeof(dest), src)))
  4. printf(TEXT("실패\n"));
  5. printf(dest);

위의 코드를 실행해 보면 왜 StringCbCopy가 안전한지를 알 수 있다. 위 프로그램을 실행하면 dest값으로 Hello가 출력된다. 왜냐하면 dest의 크기인 6이 StringCbCopy함수 내부로 들어갔기 때문에 거기까지만 복사가 진행된 것이다. 더 이상 복사할 경우 버퍼 오버런이 발생하기 때문이다.

view plaincopy to clipboardprint?
  1. HRESULT StringCchPrintf(
  2. LPTSTR pszDest,
  3. size_t cchDest,
  4. LPCTSTR pszFormat,
  5. ...
  6. );

StringCbPrintf 함수의 원형이다. 이 함수는 sprintf와 동일한 기능을 한다. pszDest에는 출력될 버퍼를, cchDest에는 pszDest에 저장할 수 있는 글자 수를, 끝으로 pszFormat에는 포맷 문자열을 넣으면 된다. 아래와 같이 사용할 수 있다.

view plaincopy to clipboardprint?
  1. TCHAR buffer[MAX_PATH];
  2. StringCchPrintf(buffer, MAX_PATH, "%s", TEXT("Hello World"));

문자열을 다루는 일은 프로그래밍 과정에서 광범위 하게 사용된다. 일부 프로그램은 문자열 처리 과정이 프로그램의 전부이기도 하다. 이처럼 문자열 처리 작업은 많이 사용되는 만큼 가장 많은 버그와 보안 허점이 나오는 곳이기도 하다. 이러한 문제를 해결하는 가장 좋은 방법은 기존의 불완전한 함수들을 사용하지 않는 것이다. 이런 이유 때문에 strsafe.h를 프로젝트에 포함시키게 되면 표준 문자열 함수를 사용하는 부분에서는 deprecated 경고가 발생한다. 하지만 deprecated 경고를 강제로 무시하고 싶은 상황도 있다. 어쩔 수 없이 써야 하는 라이브러리 코드 등에서 표준 문자열 함수를 사용한 경우가 대표적이다. 이럴 때 경고를 강제로 끄기 위해서는 strsafe.h를 포함시키는 부분 앞에 STRSAFE_DEPRECATE를 정의해주면 된다. 아래와 같이 include를 시키면 표준 문자열 함수에 대한 경고가 발생하지 않는다.

view plaincopy to clipboardprint?
  1. #define STRSAFE_DEPRECATE
  2. #include <strsafe.h>

String 계열의 함수가 안전하고 좋은 것임은 사실이다. 하지만 기존의 ANSI C/C++ 의 표준 문자열 함수들로 작성된 프로젝트를 String 계열의 함수로 교체하는 작업은 신중하게 결정해야 한다. 언뜻 보기에는 함수명을 바꾸는 간단한 작업처럼 보이지만 실상은 그렇지 않다. 기존 라이브러리 함수들을 사용하는 대부분의 코드의 경우 함수로 출력 버퍼의 크기를 전송하지 않기 때문에 호출하는 쪽과 함수 코드를 전체적으로 수정해야 한다. 이런 이유로 대부분의 경우 String계열로 코드를 고침으로써 얻는 보안 효과보다 더 많은 버그가 수정 도중에 발생한다. 따라서 기존의 프로젝트 코드를 변경하는 일은 신중히 검토한 후 결정하도록 하자.

말은 쓰는 사람의 혼을 담는 그릇이라고 한다. 이와 마찬가지로 코드는 프로그래머의 혼을 담는 그릇이 될 수 있다. 앞으로 새롭게 작성하는 프로젝트에는 안전한 문자열 함수를 쓰고 문자열 포인터가 전달되는 곳으로는 항상 크기를 같이 전달하도록 하자. 이보다 좀 더 좋은 방법은 되도록 직접적인 문자열 포인터의 사용을 줄이고 string이나 CString등의 C++ 클래스를 사용하는 것이다.

 

출처: http://www.jiniya.net/lecture/techbox/strsafe.html

저작자표시 (새창열림)

'c & c++' 카테고리의 다른 글

10년 만에 새로 태어나는 ‘모던 C++’  (0) 2014.11.04
IsUtf8() - 문자열이 Utf8인지 체크하는 함수  (0) 2013.08.06
extern "C" 에 관하여...  (0) 2013.04.16
Posted by hyeonk

윈도우 서버 환경에서, 최대 생성 가능한 소켓(socket) 연결 수는 얼마일까?

개발이야기 2013. 4. 16. 15:55

문득 윈도우 서버에서 최대 생성 가능한 소켓 수가 얼마인지 궁금해 검색을 해봤다.

관련 내용이 있었는데, 역시 흥미있는 내용이었다..

 

윈도우 서버 환경에서, 최대 생성 가능한 소켓(socket) 연결 수는 얼마일까?


사실, 처음 이 질문에 의문을 느꼈을 때 제 심중의 대답은 Port 수 제한이었습니다. unsigned short(2byte) 이니까 65535 일 텐데 그나마 시스템에서 사용하는 포트를 제외해야 하니 약 60K 정도는 생성할 수 있을 것이라는 계산이었습니다.

서버 한대에 6만 개의 클라이언트라면 그다지 나쁘지 않은 연결 수인 것 같았지만, 최근의 64비트 다중 코어/소켓을 장착한 고성능 서버들이 출현하는 상황에서 거의 무한대에 가까운 16byte 주소값을 갖는 IPv6에서도 포트를 나타내는 타입이 USHORT 인 것을 보고는 다소 놀랬습니다.

=== ws2ipdef.h ===
typedef struct sockaddr_in6 {
ADDRESS_FAMILY sin6_family; // AF_INET6.
USHORT sin6_port; // Transport level port number.
ULONG sin6_flowinfo; // IPv6 flow information.
IN6_ADDR sin6_addr; // IPv6 address.
union {
ULONG sin6_scope_id; // Set of interfaces for a scope.
SCOPE_ID sin6_scope_struct;
};
} SOCKADDR_IN6_LH, *PSOCKADDR_IN6_LH, FAR *LPSOCKADDR_IN6_LH;


여전히 미래에도 60K 동시 연결만을 제공한다는 걸까요?

도저히 그럴 수는 없다는 상식으로, 검색을 해보았습니다. 그런데... 꽤나 의외더군요. 이에 대한 의문을 갖는 사람도 별로 없었을 뿐더러, 대부분은 답변까지 포함해서 틀린 답들 뿐이었습니다. (일부 답변은 Windows 2000만 있었을 당시라서 그 때에는 맞는 답일 수 있습니다.)

이론상 접속 가능한 최대 인원은?
; http://www.gpgstudy.com/forum/viewtopic.php?topic=5370

다시한번질문드립니다.소켓의 한계...한피씨의 서버용량은???
; http://www.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_qna&no=15833

소켓 생성시 최대개수는..... 얼마나..
; http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=50&MaeulNo=20&no=206826&ref=206665

Windows에서 열 수 있는 Socket 수 얻는 방법
; http://bspfp.pe.kr/63

WSAAsyncSelect 로가능한 소켓갯수는...
; http://www.tipssoft.com/bulletin/board.php?bo_table=QnA&wr_id=16299


사실, 검색도 힘들었는데... 디아블로인가... ^^; 게임에서 제공되는 소켓 아이템이라는 동일 이름 때문이었습니다. (다시 한번 놀랬지만, 게임 유저들의 그 참여/공유 정신은 대단한 것 같습니다. ^^)

다음 차례로, 외국 자료가 남았군요. 검색을 해보니, 진단이 딱 나옵니다.

One Million TCP Connections...
; http://www.serverframework.com/asynchronousevents/2010/12/one-million-tcp-connections.html


윈도우상에서의 이론 상 한계는 "16,777,214" 이라고 합니다. 이 정도면 결국 실질적인 한계가 문제인데, 아래의 글에서 잘 정리해 주고 있습니다.

How to support 10,000 or more concurrent TCP connections
; http://www.serverframework.com/asynchronousevents/2010/10/how-to-support-10000-concurrent-tcp-connections.html


 

  • Data copies
  • Context switches
  • Memory allocation
  • Lock contention


즉, 서버 스펙도 따라야 하고, 해당 응용 프로그램의 메모리/로직에 따라서 천차만별이 된다는 것이죠. ^^

참고로, 아래는 일반적인 threshold 값들인데 아마도 Windows Server 2003 기준의 값인 것 같습니다. 운영체제마다 변경된 부분이 있을 테니 적용할 때는 적절하게 감안을 해주셔야 할 것입니다.

Configure the max limit for concurrent TCP connections
; http://smallvoid.com/article/winnt-tcpip-max-limit.html


 




그런데, 아직... 의문이 안 풀린 분들이 있을 텐데요. 과연 어떻게 포트 번호 범위를 넘어서는 16,777,214 값이 나오게 된 걸까요? 이에 대한 설명은 위에서 소개한 "One Million TCP Connections..." 글의 댓글에서 글쓴이가 쉽게 설명해 주고 있습니다.

No, that's a common misconception. You're limited to the local ports when making outbound connections as each connection consumes a local port and they are limited to 65535 as you point out and when you take into account the number of ports already in use for other services and any connections currently in TIME_WAIT the maximum number of outbound ports is usually at most 50k.

Inbound ports are identified by a tuple that consists of the local ip and port and the remote ip and port and so are not limited in the same way. I've run tests whereby a simple server on very modest hardware supported more than 70,000 concurrent active connections - the test server and client that I used can be found here: http://www.lenholgate.com/archives/000568.html



오~~~ 역시 머리 좋은 사람들은 다르군요. ^^ 어차피 내부에서 해당 소켓을 식별만 하면 되는데 굳이 2바이트 정수로 제한할 필요없이 구분키의 범위를 연결을 시도한 측의 IP/Port를 함께 포함하니 자연스럽게 65,535 개의 한계가 없어져버립니다. 실제로 글쓴이는 760 MB 메모리만을 가진 Windows Server 2003 시스템으로 7만 개의 동시 연결을 테스트했다고 합니다.

재미있군요. 직접 테스트 해보실 분들 계신가요? 700 MB 정도에 7만 개면, 24 GB 메모리면 테스트에 사용한 동일한 서버 프로그램으로 210만 개는 무난하게 나온다는 얘기가 되는 군요. 그럼, 서버는 그 정도 사양으로 한 대 준비하면 될 것 같고. 반면에 클라이언트는 제법 준비를 해둬야 합니다. 왜냐 하면 클라이언트 측은 여전히 65,535 포트 범위 제한이 있기 때문에, 100만개 연결 테스트만 해도 20 대 정도가 넘게 필요합니다. Virtual NIC의 특별한 제한이 없다면 가상 PC를 20개 정도 마련해야 겠군요. (참고로, 가정용 무선 Access Point로는 네트워크 연결 테스트하지 마세요. ^^ 제 경우에는 천 개만 넘어도 네트워크가 멈춰버렸습니다.)

혹시, 환경 구성해서 테스트 하시는 분이 계시면 결과 좀 공유 부탁드리겠습니다. ^^

 

출처: http://blog.naver.com/techshare/100118458092

저작자표시 (새창열림)

'개발이야기' 카테고리의 다른 글

프레임워크란?  (0) 2016.07.26
프로그래밍에서 SIDE EFFECT 란?  (0) 2015.10.14
boost 라이브러리 집중 분석  (0) 2015.10.13
개인 프로젝트를 위한 프로젝트 매니지 먼트와 오픈소스  (0) 2013.05.07
Posted by hyeonk

extern "C" 에 관하여...

c & c++ 2013. 4. 16. 11:00

extern "C"에 대하여 알아보자.

컴파일러는 링커가 링킹작업시 오브젝트간 함수 이용 및 위치를 파악할 수 있도록, 컴파일시 사용된 함수에 관련한 정보를 오브젝트 파일에 기록하며, 이러한 정보를 linkage라고 한다.

그런데 C 와 C++을 혼합하여 사용 시, 함수이용에 문제가 발생할수 있는데, 이는 두 언어간의 linkage방식이 틀리는데 기인한다.

linkage이란 컴파일 시 함수이름 앞 또는 뒤에 '_' 등의 심볼을 덧붙이는 것을 말하는것으로, C 와 C++은 컴파일시 오브젝트 파일에 함수명, 변수명등에 심볼을 기록하는 방식이 다르다.

C에서는 함수의 이름이 유일하기 때문에(즉 overloading을 지원하지 않기때문에) 함수 앞에 '_' 등의 심볼만을 붙이면 된다. 하지만 C++에서는 overloading을 지원하기 때문에 같은 이름의 함수를 여러개 가질 수 있으므로, 이에 따라 함수를 구분하기 위해서는, 함수이름만으로 구분할 수 없게된다. 그러므로 인자의 개수와 데이터형에 대한 정보까지 넣게되어(이러한 방식을 mangled name이라한다.), linkage 정보가 상이하게 된다.

그러므로 C와 C++ 을 혼합하는 프로그램에서는, link시 함수명을 각각의 방식으로 찾을 수 있도록 C인지, C++인지를 명시해주어야 하며, 이때 extern "C" 는 linkage에 대한 지시자 역할을 한다.

extern "C"는 C++의 linkage방식을 사용하지 않고, C의 linkage방식을 사용하라고 컴파일러에게 알려주는 역할을 한다.

#ifdef __cplusplus
extern "C" {
#endif

int func1();
int func2();

#ifdef __cplusplus
}
#endif

 

출처: http://jimbo73.egloos.com/1486292

저작자표시 (새창열림)

'c & c++' 카테고리의 다른 글

10년 만에 새로 태어나는 ‘모던 C++’  (0) 2014.11.04
IsUtf8() - 문자열이 Utf8인지 체크하는 함수  (0) 2013.08.06
안전한 문자열 함수들  (0) 2013.05.03
Posted by hyeonk
이전페이지 다음페이지
블로그 이미지

hello world! hyeonk lab.

by hyeonk

공지사항

    최근...

  • 포스트
  • 댓글
  • 트랙백
  • 더 보기

태그

글 보관함

«   2025/12   »
일 월 화 수 목 금 토
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

링크

카테고리

전체 (44)
ios (1)
mfc & winAPI (17)
c & c++ (4)
java (1)
eclipse (1)
visual_studio (2)
javascript (3)
asp (1)
oracle (3)
개발이야기 (5)
윈도우 일반 (2)
etc (2)
reference (2)
personal_reference (0)

카운터

Total
Today
Yesterday
방명록 : 관리자 : 글쓰기
hyeonk's Blog is powered by daumkakao
Skin info material T Mark3 by 뭐하라
favicon

hyeonk lab

hello world! hyeonk lab.

  • 태그
  • 링크 추가
  • 방명록

관리자 메뉴

  • 관리자 모드
  • 글쓰기
  • 전체 (44)
    • ios (1)
    • mfc & winAPI (17)
    • c & c++ (4)
    • java (1)
    • eclipse (1)
    • visual_studio (2)
    • javascript (3)
    • asp (1)
    • oracle (3)
    • 개발이야기 (5)
    • 윈도우 일반 (2)
    • etc (2)
    • reference (2)
    • personal_reference (0)

카테고리

PC화면 보기 티스토리 Daum

티스토리툴바