상세 컨텐츠

본문 제목

PRE02-C. 매크로로 치환될 영역은 반드시 괄호로 둘러싸야 한다

개발 환경/CERT - 취약점

by cepiloth 2021. 6. 1. 18:30

본문

728x90
반응형

매크로로 치환될 영역을 괄호로 둘러싸면 근처의 표현식으로 인해 우선순위가 바뀌는 일을 방지할 수 있다. PRE00-C 함수형의 매크로보다는 인라인이나 정적 함수를 사용하라와 PRE01-C 매크로에서는 매개 변수에 괄호를 사용하라를 참조하라.

 

부적절한 코드 예

아래 CUBE() 매크로 정의는 치환될 영역을 괄호로 둘러싸고 있지 않아 부적절하다.

#define CUBE(X) (X) * (X) * (X)
int i = 3;
int a = 81 / CUBE(i);

따라서 다음과 같이 호출하면,

int a = 81 / CUBE(i);

이렇게 확장되므로,

int a = 81 / i * i * i

결과는,

int a = (((81 / i) * i) * i);
/* 243 이 된다 */

처럼 의도와 다르게 된다.

 

해결방법

치환될 영역을 괄호로 둘러싸면 CUBE()를 호출할 때 정확하게 치환된다.

#define CUBE(X) ((X) * (X) * (X))
int i = 3;
int a = 81 / CUBE(i);

하지만 이 방법은 PRE00-C 함수형의 매크로보다는 인라인이나 정적 함수를 사용하라를 위반하므로 매크로 대신 인라인 함수를 사용하는 편이 더 좋다.

 

부적절한 코드 예

이 코드에서는 EOF가 -1로 정의돼 있다. 매크로로 치환될 부분에는 - 연산자와 숫자 리터럴 1이 들어간다.

#define EOF -1
/* ... */
if (getchar() EOF) {
  /* ... */
}

 

프로그래머가 getchar() != EOF에서 비교 연산자를 실수로 누락했다. 이렇게 되면 매크로 치환 이후 조건 표현식이 getchar()-1로 되어 단항 연산으로 처리되므로 부적절하게 평가된다. 언어 규칙상으로 맞지만 프로그래머가 의도한 것은 아니다.

EOF에 대한 -1 정의를 괄호로 둘러싸면 매크로 치환이 정확해진다.

#define EOF (-1)

이렇게 수정하면 예제의 코드는 매크로 치환 이후 getchar()(-1) 처럼되므로 언어 규칙상 맞지 않아 컴파일되지 않는다. 위에서 EOF 다음에 공백이 하나 있음을 주의하자. 공백이 없으면 함수형 매크로처럼 인식되고 매개변수로서는 부적절한 -1을 가지고 비정상적인 매크로 처리를 한다.

 

해결 방법

매크로 정의를 열거형 상수로 치환하면 된다.

enum { EOF = -1 }
/* ... */
if (getchar() != EOF) {
  /* ... */
}

 

예외

PRE02-EX1 : 매크로가 한 개의 식별자나 함수로 치환되는 경우에는 치환되는 영역 근처의 다른 표현식에 의해 영향받지 않으므로 치환되는 영역을 괄호로 둘러쌀 필요가 없다.

#define MY_PID getpid()

 

728x90
반응형

관련글 더보기

댓글 영역