項目經驗之談 —— 利用編譯器及C語言特性進行內存邊界檢測

1.前言

在C語言中,邊界檢測總是一個讓程序員頭疼的問題,一不小心程序就崩潰了。C語言本身並沒有提供邊界檢測的語法。但我們可以利用語言本身的一些特性及編譯器進行邊界檢查。

2.校驗內存邊界

#define VERIFY_BOUNDARY(name,R) static char name ## dummy [sizeof(struct { unsigned char dummy:((R)?1:-1);})]  __attribute__ ((unused))

3.源碼

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>

#define ARRAY_CARDINALITY(Array) (sizeof(Array) / sizeof(*(Array)))

#define VERIFY_BOUNDARY(name,R) static char name ## dummy [sizeof(struct { unsigned char dummy:((R)?1:-1);})]  __attribute__ ((unused))

enum {
    VIR_DAEMON_ERR_NONE = 0,
    VIR_DAEMON_ERR_PIDFILE,
    VIR_DAEMON_ERR_RUNDIR,
    VIR_DAEMON_ERR_INIT,
    VIR_DAEMON_ERR_SIGNAL,
    VIR_DAEMON_ERR_PRIVS,
    VIR_DAEMON_ERR_NETWORK,
    VIR_DAEMON_ERR_CONFIG,
    VIR_DAEMON_ERR_HOOKS,
    VIR_DAEMON_ERR_AUDIT,

    VIR_DAEMON_ERR_LAST
};

//========================================================================
int virEnumFromString(const char *const*types,
                      unsigned int ntypes,
                      const char *type)
{
    size_t i;
    if (!type)
        return -1;

    for (i = 0; i < ntypes; i++)
        if (0 == strcmp(types[i], type))
            return i;

    return -1;
}

const char *virEnumToString(const char *const*types,
                            unsigned int ntypes,
                            int type)
{
    if (type < 0 || type >= ntypes)
        return "unknow";

    return types[type];
}

//========================================================================

# define VIR_ENUM_IMPL(name, lastVal, ...)                               \
    static const char *const name ## TypeList[] = { __VA_ARGS__ };      \
    VERIFY_BOUNDARY(name,(ARRAY_CARDINALITY(name ## TypeList) == lastVal));\
    const char *name ## TypeToString(int type) {                        \
        return virEnumToString(name ## TypeList,                        \
                               ARRAY_CARDINALITY(name ## TypeList),     \
                               type);                                   \
    }                                                                   \
    int name ## TypeFromString(const char *type) {                      \
        return virEnumFromString(name ## TypeList,                      \
                                 ARRAY_CARDINALITY(name ## TypeList),   \
                                 type);                                  \
    }

# define VIR_ENUM_DECL(name)                             \
    const char *name ## TypeToString(int type);         \
    int name ## TypeFromString(const char*type);

//========================================================================

VIR_ENUM_DECL(virDaemonErr);
VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
              "Initialization successful",
              "Unable to obtain pidfile",
              "Unable to create rundir",
              "Unable to initialize libvirt",
              "Unable to setup signal handlers",
              "Unable to drop privileges",
              "Unable to initialize network sockets",
              "Unable to load configuration file",
              "Unable to look for hook scripts",
              "Unable to initialize audit system");




int
main(int argc, char *argv[])
{
    printf("[ERR]: %s\n\r",virDaemonErrTypeToString(VIR_DAEMON_ERR_HOOKS));
    return 0;
}

4.執行結果

leon@netview:~/test/error$ ./error
[ERR]: Unable to look for hook scripts

5.修改數組大小

上述執行結果是因爲預期的數組大小跟實際的一致,可以通過修改數組大小,來檢查效果。
修改數組大小後,編譯結果:

leon@netview:~/test/error$ gcc -Wall -o error error.c 
error.c:15:74: error: negative width in bit-field ‘dummy’
 #define VERIFY_BOUNDARY(name,R) static char name ## dummy [sizeof(struct { unsigned char dummy:((R)?1:-1);})]  __attribute__ ((unused))
                                                                          ^
error.c:61:5: note: in expansion of macro ‘VERIFY_BOUNDARY’
     VERIFY_BOUNDARY(name,(ARRAY_CARDINALITY(name ## TypeList) == lastVal));\
     ^
error.c:83:1: note: in expansion of macro ‘VIR_ENUM_IMPL’
 VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
 ^
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章