반응형
버퍼(buffer)란?
흔히 우리가 변수로 사용하는 buffer의 origin인데, 실제 데이터가 실행 함수에 의해 입출력을 진행할 때, 바로 입력 혹은 출력이 되는 것이 아니라 버퍼(buffer)라는 공간에 저장이 된 이후에 동작하게 된다. 이는 데이터를 효율적으로 처리하기 위함인데, 매번 데이터를 처리하는 것보다 일정 크기만큼 데이터를 모아둔 뒤 처리하는 것이 CPU 사용 횟수나 메모리 접근 횟수를 줄일 수 있다.(system call file I/O와 다르게 FILE *을 이용한 file I/O는 중간 buffer를 이용하여 system call 횟수를 줄임으로써 자원을 효율적으로 사용한다.)
그러나 이러한 버퍼의 기능때문에 다양한 예기치 않은 문제를 만날 수 있는데, 대부분 버퍼가 완전히 비워지지 않아 문제가 발생한다. 버퍼 안에 개행문자('\n')가 남아있어 이 후의 입력에 영향을 미치던가, 버퍼의 설정때문에 출력버퍼가 바로 비워지지않아 프로그램 흐름에 문제가 발생한다던가 하는 것들이 바로 그 예시들이다. 나 역시 그런한 문제가 발생했고, 아래 내가 이 글을 쓰게된 원인이 있다. 아래의 경우는 출력버퍼를 제대로 비워주지 않아서 문제가 발생한 경우이다.
출력버퍼 문제 발생 예시
#include<stdio.h>
void printmenu(){
puts("hello");
printf(">> ");
}
int main(){
char str[256];
printmenu();
read(0,str,0x100);
return 0;
}
아무튼 이런 입출력버퍼때문에, 위 경우와 같이 프로그램 개발에 예기치 않은 문제를 만날 수 있으므로, 아래의 setvbuf() 함수를 통해, 입출력 버퍼의 설정을 바꾸는 방법을 알아보도록 하자.
setvbuf() 함수
스트림 버퍼링 방식과 버퍼의 크기를 설정하는 함수로, 다음과 같다.
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int type, size_t size);
/*
stream
stdin(표준입력, 0)
stdout(표준출력, 1)
stderr(표준에러, 2)
혹은 open 등으로 생성한 파일 포인터 등이 있다.
buf
입출력 버퍼로 사용할 메모리. NULL이면 malloc을 통해 내부적으로 버퍼공간을 생성한다.
type
_IOFBF(0) Full buffering 버퍼가 가득차면 버퍼를 비운다. buf를 시작으로 size만큼의 크기를 가진 버퍼를 사용한다.
_IOLBF(1) Line buffering 행 단위 버퍼링이 사용된다. 개행문자('\n')가 사용되거나, 버퍼가 가득 차거나, 입력이 요청되면 버퍼를 비운다.
_IONBF(2) No buffering버퍼를 사용하지 않는다. buf와 size는 무시한다.
size
버퍼의 크기를 설정한다.
*/
Return 값
성공하면 0을 리턴하고, 유효하지 않은 값이 매개변수 리스트에 지정되거나 요청을 수행할 수 없는 경우 0이 아닌 값을 리턴한다.
입출력 버퍼 다루기 예시
setvbuf()
setvbuf(stdout, 0, 0, 10); // 출력 버퍼의 크기를 10으로 설정. 버퍼가 가득 찬 뒤 출력된다.
setvbuf(stdout, 0, 2, 0); // CTF 문제에서 볼 수 있는 사용. 버퍼를 없앤다.
setvbuf(stdin, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
/*표준 스트림이 아닌 파일 포인터에서 사용할 경우*/
#include <stdio.h>
#define BUF_SIZE 1024
char buf[BUF_SIZE];
FILE *stream1, *stream2;
int main(void)
{
stream1 = fopen("myfile1.dat", "r");
stream2 = fopen("myfile2.dat", "r");
/* stream1 uses a user-assigned buffer of BUF_SIZE bytes */
if (setvbuf(stream1, buf, _IOFBF, sizeof(buf)) != 0)
printf("Incorrect type or size of buffer\n");
/* stream2 is unbuffered */
if (setvbuf(stream2, NULL, _IONBF, 0) != 0)
printf("Incorrect type or size of buffer\n");
/* This is a program fragment and not a complete function example */
}
버퍼 비우기 예시
while (getchar() != '\n');} // 입력 버퍼에서 문자를 하나씩 꺼내며, 개행문자('\n')를 꺼내면 중단하게 된다.
fflush(stdout); // 출력 버퍼를 강제로 비운다.
fflush(stdin); // 윈도우에서만 동작 가능. 입력 버퍼를 강제로 비운다. C 언어 표준에서 정의되지 않은 행동이기에 컴파일러마다 다르게 동작한다.
참고 :
반응형
'Computer Science% > System' 카테고리의 다른 글
LibFuzzer w\ OpenJpeg 코드 작성 후 퍼징 결과 제출 (0) | 2020.06.14 |
---|---|
Classic하지 않은 함수의 프롤로그와 에필로그 (0) | 2019.04.25 |
어쩌다보니 시작한 checksec 분석글 (0) | 2019.03.17 |
Shellcode (0) | 2018.02.08 |
커널모드와 유저모드 (0) | 2017.08.31 |