이 코드를 사용합니다.
while ( scanf("%s", buf) == 1 ){
임의 길이의 문자열을 전달할 수 있도록 가능한 버퍼 오버플로를 방지하는 가장 좋은 방법은 무엇입니까?
예를 들어 다음을 호출하여 입력 문자열을 제한 할 수 있다는 것을 알고 있습니다.
while ( scanf("%20s", buf) == 1 ){
하지만 사용자가 입력 한 모든 것을 처리 할 수 있기를 원합니다. 아니면 scanf를 사용하여 안전하게 수행 할 수없고 fgets를 사용해야합니까?
답변
Kernighan과 Pike는 저서 The Practice of Programming (읽을 가치가 있음)에서이 문제를 논의하고 함수 패밀리에 snprintf()
전달할 올바른 버퍼 크기를 가진 문자열을 만드는 데 사용하여 문제를 해결합니다 scanf()
. 사실상:
int scanner(const char *data, char *buffer, size_t buflen)
{
char format[32];
if (buflen == 0)
return 0;
snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
return sscanf(data, format, buffer);
}
이것은 여전히 ’버퍼’로 제공되는 크기로 입력을 제한합니다. 더 많은 공간이 필요하면 메모리 할당을 수행하거나 메모리 할당을 수행하는 비표준 라이브러리 기능을 사용해야합니다.
참고의 POSIX 2008 (2013) 버전 것으로 scanf()
기능의 가족이 형식 수정 지원 m
문자열 입력에 대한 (할당 할당 문자) ( %s
, %c
, %[
). char *
인수 를받는 대신 char **
인수를 사용하고 읽는 값에 필요한 공간을 할당합니다.
char *buffer = 0;
if (sscanf(data, "%ms", &buffer) == 1)
{
printf("String is: <<%s>>\n", buffer);
free(buffer);
}
은 IF sscanf()
함수는 모든 변환 사양을 만족하지, 모든이에 할당 된 메모리 %ms
-like 변환은 함수가 반환하기 전에 해제됩니다.
답변
gcc를 사용하는 경우 GNU 확장 a
지정자를 사용하여 scanf ()가 입력을 저장할 메모리를 할당하도록 할 수 있습니다.
int main()
{
char *str = NULL;
scanf ("%as", &str);
if (str) {
printf("\"%s\"\n", str);
free(str);
}
return 0;
}
편집 : Jonathan이 지적했듯이 scanf
지정자가 다를 수 있고 ( %m
) 컴파일 할 때 특정 정의를 활성화해야 할 수 있으므로 man 페이지를 참조 해야합니다.
답변
대부분의 경우 fgets
및 sscanf
작업을 수행합니다. 다른 것은 입력이 잘 포맷 된 경우 자신 만의 파서를 작성하는 것입니다. 또한 두 번째 예제를 안전하게 사용하려면 약간의 수정이 필요합니다.
#define LENGTH 42
#define str(x) # x
#define xstr(x) str(x)
/* ... */
int nc = scanf("%"xstr(LENGTH)"[^\n]%*[^\n]", array);
위는 줄 바꿈 ( \n
) 문자를 포함하지 않고 입력 스트림을 버립니다 . getchar()
이것을 사용하려면를 추가해야합니다 . 또한 스트림의 끝에 도달했는지 확인하십시오.
if (!feof(stdin)) { ...
그게 다야.
답변
직접 사용 scanf(3)
및 그 변형은 많은 문제를 제기합니다. 일반적으로 사용자 및 비대화 형 사용 사례는 입력 라인으로 정의됩니다. 충분한 객체가 발견되지 않으면 더 많은 줄이 문제를 해결할 수있는 경우는 드물지만 이것이 scanf의 기본 모드입니다. (사용자가 첫 번째 줄에 숫자를 입력하는 것을 몰랐다면 두 번째와 세 번째 줄은 도움이되지 않을 것입니다.)
적어도 fgets(3)
프로그램에 필요한 입력 라인 수 를 알고 있고 버퍼 오버플로가 발생하지 않으면 …
답변
입력 길이를 제한하는 것이 확실히 더 쉽습니다. 루프를 사용하여 한 번에 조금씩 읽고 필요에 따라 문자열 공간을 다시 할당하여 임의의 긴 입력을 허용 할 수 있습니다.
그러나 그것은 많은 작업이므로 대부분의 C 프로그래머는 임의의 길이로 입력을 잘라냅니다. 이미 알고 있다고 가정하지만 fgets ()를 사용하면 임의의 양의 텍스트를 허용 할 수 없습니다. 여전히 제한을 설정해야합니다.
답변
문자열에 필요한 메모리를 할당하는 함수를 만드는 것은 그리 많은 작업이 아닙니다. 그것은 내가 얼마 전에 작성한 약간의 c- 함수이며, 나는 항상 그것을 문자열로 읽는 데 사용합니다.
읽기 문자열을 반환하거나 메모리 오류가 발생하면 NULL을 반환합니다. 그러나 문자열을 free ()해야하며 항상 반환 값을 확인해야합니다.
#define BUFFER 32
char *readString()
{
char *str = malloc(sizeof(char) * BUFFER), *err;
int pos;
for(pos = 0; str != NULL && (str[pos] = getchar()) != '\n'; pos++)
{
if(pos % BUFFER == BUFFER - 1)
{
if((err = realloc(str, sizeof(char) * (BUFFER + pos + 1))) == NULL)
free(str);
str = err;
}
}
if(str != NULL)
str[pos] = '\0';
return str;
}