gets를 대체해서 쓸만한 함수가 있을까요?
글쓴이: itzmi / 작성시간: 일, 2006/11/19 - 12:23오전
표준 입출력으로 입력받는데,
gets쓰면 자꾸 warning이 나길래 여기 글을 읽어봤는데 보안상 문제가 있다고 하네요.
제가 짜는거야 아주 기초적인 것이라서 그런 걱정까지 할 필요는 없는데, warning이 뜨는건
영 찝찝해서 대체할만한 함수를 찾고 있습니다. gets대신 fgets나 read를 쓰는 것이 좋겠다는
글들이 많았는데, fgets나 read는 파일관련 함수라서 어떻게 해야할 지 잘 모르겠습니다.
scanf를 쓰자니 공백이 들어가면 제대로 입력을 안받고 해서.. 기초수준에서 할 때 제대로
배워놔야 나중에 고생 안하겠죠?
답변 부탁드릴겠습니다~
Forums:
readline ..
readline library가 있어요 ..
man readline ;;
gets는 입력을
gets는 입력을 받아들이는 문자열 버퍼 크기를 따로 명시하지 않기 때문에 입력받은 문자열의 길이가 문자열 버퍼를 넘어가는 것을 방지할 수 없고 그런 문제 발생시 버퍼 오버플로우를 일으켜서 잠재적인 보안 문제에 노출되도록 만듭니다.
따라서 gets 대신 버퍼 크기를 따로 명시해 줄 수 있는 fgets를 쓰는 것이 정답입니다. 사용법은 다음과 같습니다.
#define STRING_SIZE 80 /* 적당한 크기를 잡는다. 경우에 따라서 얼마든지 더 큰 크기로 사용 가능. */
int main(void)
{
char string[STRING_SIZE];
/* gets(string); XXX: gets 함수는 string의 크기가 어느 정도인지 알지 못한다. 따라서 STRING_SIZE 이상의 길이를 가진 문자열 입력시 정상 작동을 보장할 수 없다. */
fgets(string, STRING_SIZE, stdin); /* 세번째 인자를 stdin으로 주면 키보드에서 입력을 받는다. 버퍼 길이를 따로 명시해 주고, 입력받은 길이가 버퍼 크기를 초과하더라도 버퍼 범위 안에서만 문자열을 받아들인다. */
printf("%s\n", string);
return 0;
}
----
mono* in the swirl
----
http://www.planetmono.org
아니면
큰 프로그램을 짜시는게 아니라면...
카운팅 변수(정수)를 만드시고 그걸 이용해서 while문과 sizeof나 몇가지 함수나 예약문을 사용하고 해서 getc나 fgetc로 한자 한자 읽어서 길이를 검사하고 제한 길이가 되면 그 뒤의 것은 무시해 버리게 하는 방법도 있습니다. while, for if, else fgetc나 getch.. 이정도만 가지고도 충분히 구현 가능합니다. 이 방법도 한번 생각 해 보심이... 하지만 편한건 fgets 등이겠죠. 근대 fgets는 문자열 뒤에 리턴문자를 집어 넣는 다는 것을 기억하시고 이걸 꼭 문자열 자체에선 제거 해 주시기 바랍니다. 이건 조금 머리 스시면 간단합니다.
----
Lee Yeosong(이여송 사도요한)
E-Mail: yeosong@gmail.com
MSN: ysnglee2000@hotmail.com
----
웃음... 행복... 평화... (진정한...) 희망... 사랑... 이 세상 모든것이 그렇다면 얼마나 좋을까...(꿈 속의 바램일 뿐인가...)
사람천사
제가 예전에 보았던
제가 예전에 보았던 책에는 fgets와 sscanf를 사용하더군요. 오래된 책이라 신뢰는 하지 마시구요.
fgets, read가 파일 관련 함수라 걸린다고 하셨는데 리눅스에서의 경험에 의하면 표준 입출력도 파일 맞습니다. 전 루비로 프로그램을 짜는데 여기서도 표준 입출력을 다른 파일과 별반 다르게 취급하지 않습니다.
근데 저도 차라리 readline을 사용하시는 게 어떨지 생각해 봅니다. 명령행 인터페이스의 거의 표준이랄까... 사용법이 좀 복잡할려나요? 그래도 한 번 익혀두시면 두고두고 좋지 않을까 하는 생각이 듭니다.
--
마잇
--
마잇
감사합니다.
답변 감사드려요. 해결하러 가봐야겠습니다. 정말 오묘하고도 괴로운(?) 길이네요 ㅠㅠ
2006.7.6 제대
C 기초다지기 에서 본 내용인데
예전에 유닉스 프로그래머가 gets로 쓰던 시절인가 ㅡㅡ;;
암튼 누군가가 바이러스를 유포했다고 하네요
gets()가 메모리 크기를 검사하지 않는다고 하던데;;
이 내용이 사실인가요??;;
gets()가 받아들이는
gets()가 받아들이는 인자를 보시면 char * 하나만을 받으므로 크기를 검사할 방법이 없습니다.
fgets()는 File *를 빼고도 버퍼 사이즈와 버퍼의 char *, 이렇게 두 가지를 받습니다.
get대신 stdin으로 fgets()를 쓰시면 같은 효과에 보안상으로는 더 낫습니다.
노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5
> scanf를 쓰자니
> scanf를 쓰자니 공백이 들어가면 제대로 입력을 안받고 해서..
>
scanf() 로도 가능합니다.
한 라인에서 버퍼를 채우고 남는 뒷부분은 무시됩니다 - 무시된 부분이
있는지 여부도 약간의 수정만으로 쉽게 확인할 수 있습니다.
물론, 아무래도 익숙한 fgets() 로 손이 가는 건 어쩔 수 없습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
어라 이건 scanf 확장 아닌가요?
정규표현식을 쓰는 것 같은데 저는 이게 표준이 아닌 확장인 것으로 알고 있었는데요.
(C90 시절부터
제가 사용한 형태는 (C90 시절부터 지원되던) 표준입니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
이 thread에서 다룬
이 thread에서 다룬 gets(), fgets(), scanf() 모두 주어진 길이의 버퍼에 문자열을 저장하는데, 크기가 더 큰 입력은 잘려 나간다는 단점이 있습니다. 따라서 release용 application을 만드는데에는 적합하지 않을 수도 있습니다. 한 줄의 길이가 N을 넘지 않을 것이다.. 라고 가정하고 프로그램을 작성하는 것은 바람직한 습관이 아닙니다.
직접 getc()나 fgetc()를 써서 한글자씩 읽은 다음 크기를 조절할 수 있는 버퍼를 준비해 두고 한 줄을 받아 들이는 함수를 작성하거나, vacancy님이 말씀하신 것처럼 readline()을 쓰는 것도 좋습니다. 단 readline()은 GNU 확장이며, 따로 readline package를 깔아야 합니다. (대부분 Linux 배포판에는 기본적으로 깔려 있을 가능성이 높습니다.)
직접 만들고자 한다면 GNU obstack (glibc에 포함, 물론 비표준)을 임시 버퍼로 쓰는 것이 편리합니다.
--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
"입력이 N을 넘지
"입력이 N을 넘지 않을 것이다"라는 "가정"은 gets() 가 하는 것이지
fgets() 나 scanf() 가 하는 것이 아닙니다. fgets(), scanf() 는 입력이
N을 넘지 않도록 "강제"할 수 있는 것입니다.
적지 않은 application 에서 지나치게 긴 라인에 대한 제한을 두는 것이
큰 무리는 아니라고 생각합니다. scanf(), fgets() 모두 잘려나간 부분에
대한 정보를 얻어올 수 있기 때문에 사용자에게 라인 길이가 초과했다는
사실을 알려줄 수 있으며, 더구나 fgets() 의 경우 (gets 는 논하지
않겠습니다) 버퍼에 담지 못한 부분이 결코 "무시"되는 것이 아닙니다
- 적지 않은 분들이 fgets() 의 행동에 대해 오해하고 계신듯 싶습니다.
readline() 이 반드시 필요한 곳이 있기는 하지만, 일반적인 입력에
readline() 을 사용하는 것에는 회의적입니다. (여담입니다만, readline
의 man page 내용 중에는 "too big & too slow"가 버그라는 내용도 있었던
것으로 기억합니다) 그리 거창하지 않은 구현이나 보다 높은 이식성을
원하신다면 표준 제공 I/O 함수와 동적 할당 함수만으로도 얼마든지 안전한
라인 입력 함수를 구성할 수 있습니다 - 다시 한번 말씀드리지만 fgets()
조합으로 전체 라인을 보존하는 입력 함수를 구성할 수 있습니다.
저 역시 부족하지만 제 나름대로 입력 함수를 하나 만들어 사용하고
있는데, 추천해 드릴만한 함수가 기억나 소개해 드리려고 인터넷을
뒤졌는데 검색이 잘 안되는군요. 나중에 기회가 되면 즐겨찾기에서 끄집어
내서 링크 걸겠습니다.
--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
다시 읽어보니, 제가
다시 읽어보니, 제가 fgets()가 주어진 버퍼보다 큰 줄의 내용은 버린다는 투로 글을 썼더군요. 전웅님께 감사합니다.
개인적으로는 한 줄을 읽는 연산은 크게 두 가지로 보고 있습니다. fdisk나 여러 interpreter (python, tcl 등)를 interactive 형태로 실행했을 때, 사용자에게서 한 줄을 읽는 것과, 파일을 읽어서 처리하는 filter 형태의 프로그램에서 한 줄을 읽는 것으로 구분하고 있습니다.
전자의 경우 느리긴 하지만 readline()을 쓰면, 간단한 editing 기능과 (GNU history library의 힘을 빌어) history도 관리할 수 있기 때문에, 큰 무리가 없을 것이라 생각합니다.
후자의 경우라면, 사용자에게 특별히 알리지 않고, 조용하게? 버퍼보다 긴 줄의 내용을 무시하는 습관은 바람직하지 않다고 생각합니다. 프로그램이 "long lines are silently truncated(긴 줄은 조용히 잘려서 처리되는)"와 같은 특징을 가지는 것은 나쁘다고 생각합니다. 물론 경고를 출력한다거나 하는 방식으로 처리해도 될 것 같습니다. 참고로 (그리 환영받는 문서는 아니지만) GNU Coding Standard에서는 그런 방식으로 처리하는 프로그램은 GNU utility로 인정받기 힘들다고 나와 있군요.
흠. 내친 김에 이 thread에서 효과적으로 한 줄을 읽는 함수를 여러분들이 제시해 보는 것은 어떨까요?
--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
readline 은 현재 gpl
readline 은 현재 gpl 이고 readline 을 쓰게 되는것 만으로 gpl 호환 라이센스를
따라야 된다는 거 같더군요. 아마도 readline 사용으로 인해 프로그램과 밀접한
연관을 가지게 됨으로서 그렇게 되는거 같습니다.
만약 라이센스 문제가 걸리신다면 다른 방법을 찾으시는게 좋겠습니다.
(bsd 라이센스의 libedit 도 있긴합니다.)
readline은 GPL이 아니라
readline은 GPL이 아니라 LGPL입니다.
정적링크만 안한다면 상관없습니다.
다른것과 헷갈려서
다른것과 헷갈려서 헛소리를 적었군요.
미심쩍어서 찾아보니 GPL이 맞군요
라이센스가 번지는걸 피하려면 쓰면 안되겠습니다.
댓글 달기