본문 바로가기

CERT C/선언과 초기화

[CERT C/선언과 초기화] (2) 가변인자 함수 사용 시 주의할 점

의미

가변인자 함수는 인자의 개수가 정해지지 않은 함수를 의미한다. 예를들면 printf, scanf 함수가 가변인자 함수이다.

 

int printf(const char*, ...);

int scanf(const char*, ...);

동작 방식

상황에 따라 들어오는 인자의 개수가 다르므로 <stdarg.h>에 정의 되어있는 함수를 이용해서 다룬다.

 

1. va_list args

 

  • 가변 인자 목록, 가변 인자의 메모리 주소를 저장하는 포인터이다.
  • va_list : char *형
  • args : argument를 가리키는 포인터

2. va_start(args, 마지막 고정인수)

  • 가변 인자를 가져올 수 있도록 포인터를 설정한다.

3. va_arg(args, type)

  • 가변 인자 포인터에서 특정 자료형 크기만큼을 가져온다.

4. va_end(args)

  • 가변 인수를 읽은 후 뒷처리를 해주어야할 필요가 있으므로 관례적으로 호출하는 것이 좋다.

예제 1. 함수 작성자와 사용자간에 규칙을 정하고 그 규칙에 의해서만 사용해야한다.

출력을 예상해보기

#include <stdio.h>
#include <stdarg.h>

enum {va_eol = -1};
double average(int first, ...);

int main()
{
    double res;

    res = average(10,30,va_eol);
    printf("res = %.2lf\n", res);

    res = average(-7, -5, -1, 1, 5 ,7, va_eol);
    printf("res = %.2lf\n", res);

    return 0;
}

double average(int first, ...)
{
    unsigned int count = 0;
    unsigned int sum = 0;

    int i = first;

    va_list args;
    va_start(args, first);
    while(i != va_eol)
    {
        sum += i;
        count++;
        i = va_arg(args, int);
    }
    va_end(args);

    return (count ? (double)sum/count : 0);
}

 

출력 :

res = 20.00

res = 2147483642.00

 

위 코드를 보면서 va_list, va_start, va_arg, va_end를 사용하는 방법을 확인한다. 두번째 res의 출력이 2147483642.00 으로 나온 이유는 int 형이 unsinged int 형으로 타입캐스팅 되면서 일어난 결과 이고 이 부분에 대해서는 이후 타입 캐스팅 관련 취약성에 대한 설명에서 자세히 다룬다.

POINT

  • 함수 작성자와 사용자간에 규칙을 정하고 그 규칙에 의해서만 사용해야한다.
  • 가변 인자를 제어하기 위해서는 va_list, va_start, va_arg, va_end 함수를 이용해서 제어한다.

참조


DCL10-C. Maintain the contract between the writer and caller of variadic functions

 

 

wiki.sei.cmu.edu/confluence/display/c/PRE00-C.+Prefer+inline+or+static+functions+to+function-like+macroswiki.sei.cmu.edu/confluence/display/c/PRE06-C.+Enclose+header+files+in+an+include+guardwiki.sei.cmu.edu/confluence/display/c/PRE10-C.+Wrap+multistatement+macros+in+a+do-while+loopwiki.sei.cmu.edu/confluence/display/c/DCL10-C.+Maintain+the+contract+between+the+writer+and+caller+of+variadic+functions