安全ではないマクロ関数

はじめに

 安全なコーディング(セキュアコーディング)の勉強中である。
セキュアコーディングのサイトを見つけたので、勉強中に試したものを記事として残す。

記事概要

 マクロ関数は、安全ではない1例が記載されていた(PRE31-C)ので、試してみた。

安全ではないマクロ関数

 下記ソースは、引数に渡された値の絶対値を返却するマクロが含まれており、そのマクロを使って計算した結果を出力するものである。
しかし、想定どおりに動作しない。
(想定)引数の絶対値
(実際)?

安全ではないマクロを使ったソース
andre@andre-VirtualBox:~/work/PRE/PRE31-C$ cat main.c
#include

#define ABS(x)  ( ((x) < 0) ? -(x) : (x) )
// 展開後=> ( ((++n) < 0) ? -(++n) : (++n) ) ★ ? の左右で n が1回ずつインクリメントされる。
int
main(void)
{
    int m = 0;
    int n1 = 1;
    int n2 = -4;
    int n3 = 0;

    m = ABS( ++(n1) );
    printf("m = %d\n", m);
    m = ABS( ++(n2) );
    printf("m = %d\n", m);
    m = ABS( ++(n3) );
    printf("m = %d\n", m);

    return 0;
}

ビルドして、動作させてみた。

andre@andre-VirtualBox:~/work/PRE/PRE31-C$ gcc -o test_main main.c
andre@andre-VirtualBox:~/work/PRE/PRE31-C$ ./test_main
m = 3   (想定)m = 2
m = 2   (想定)m = 3
m = 2   (想定)m = 1

安全に(想定どおりに)動作させるには

 inline もしくは static 関数として定義する。
下記に示す。

andre@andre-VirtualBox:~/work/PRE/PRE31-C$ cat main_legal.c
#include

inline int
abs( int x )
{
    return ( ((x) < 0) ? -(x) : (x) );
}

int
main(void)
{
    int m = 0;
    int n1 = 1;
    int n2 = -4;
    int n3 = 0;

    m = abs( ++(n1) );
    printf("m = %d\n", m);
    m = abs( ++(n2) );
    printf("m = %d\n", m);
    m = abs( ++(n3) );
    printf("m = %d\n", m);

    return 0;
}

ビルドして、想定どおりに動作するか試した。

andre@andre-VirtualBox:~/work/PRE/PRE31-C$ gcc -o main_legal main_legal.c
andre@andre-VirtualBox:~/work/PRE/PRE31-C$ ./main_legal 
m = 2   (想定)m = 2
m = 3   (想定)m = 3
m = 1   (想定)m = 1

結論

 マクロは想定したとおりに動作しないことがあるので、基本的に使わないようにする。