0

私は C にかなり慣れていないので、EV_KEY イベントを処理するすべてのイベント ハンドラーを開き、それらのファイル記述子のリストを (まだ開いている間に) 表示するユーティリティを作成しようとしています。ファイル記述子をループしようとすると、スタックエラーが発生します問題の原因を見つけるために、gcc の -Wall フラグを使用して各 C ファイルをコンパイルしようとしましたが、役に立ちませんでした。これが私のコードです:

int *get_key_handlers() {

    int *fds;
    int fd;
    int num_handlers = 0;
    struct dirent *dp;
    DIR *dir;
    char full_path[100];
    char *base_path = "/dev/input/";

    printf("Creating file descriptor array\n");
    fds = malloc(sizeof(int*)*32);   // not currently going to bother
                                     //   with more than 32 handlers

    printf("Opening event handler directory\n");
    if (!(dir = opendir(base_path))) {
        return 1;
    }

    printf("Beginning reading through directory\n");
    while ((dp = readdir(dir))) {

        if (dp->d_name && !strncmp(dp->d_name, "event", 5)) {

            // cat the base path and device name, store in full_path
            snprintf(full_path, sizeof(full_path), "%s%s", base_path, dp->d_name);
            printf("Found handler at %s\n", full_path);
            fd = open(full_path, O_RDONLY);

            printf("Detecting handler features...\n");
            unsigned char results[EV_MAX/8+1];
            memset(results, 0, sizeof(results));
            ioctl(fd, EVIOCGBIT(EV_KEY, EV_MAX), results); 
            printf("Features determined\n");
            printf("EV_KEY: %d\n", EV_KEY);
            if (test_bit(*results, EV_KEY)) {
                printf("EV_KEY feature detected on %s\n", full_path);
                fds[num_handlers] = fd;
                num_handlers++;
            } else {
                printf("EV_KEY feature NOT detected on %s\n", full_path);
                close(fd);
            }
            printf("Done with handler at %s\n", full_path);
        }
    }
    printf("Finished creating handler list\n");

    fds = realloc(fds, sizeof(int*) * num_handlers);
    printf("Handler list re-sized\n");
    return fds;
}

get_key_handlers() 関数を呼び出すコードは次のとおりです。

int main() {
    int *fds = get_key_handlers();
    int i = 0;
    for (i = 0; i < (sizeof(fds)/sizeof(int*)); i++) {
        printf("Next file descriptor: %d\n", *(fds + (i * sizeof(int*))));
    }

    free(fds);
    return 0;
}

最後に、コンパイルとリンクのために実行しているコマンドと、プログラムの実行時出力を次に示します。

tim@tim-ubuntu:~/Documents/Programming/C/clogger$ gcc -c -Wall thinput.c
thinput.c: In function ‘get_key_handlers’:
thinput.c:21:9: warning: return makes pointer from integer without a cast [enabled by default]
tim@tim-ubuntu:~/Documents/Programming/C/clogger$ gcc -c -Wall thinputtest.c
tim@tim-ubuntu:~/Documents/Programming/C/clogger$ gcc thinput.o thinputtest.o -o thinputtest
tim@tim-ubuntu:~/Documents/Programming/C/clogger$ sudo ./thinputtest
Creating file descriptor array
Opening event handler directory
Beginning reading through directory
Found handler at /dev/input/event15
Detecting handler features...
Features determined
EV_KEY: 1
EV_KEY feature NOT detected on /dev/input/event15
Done with handler at /dev/input/event15
Found handler at /dev/input/event14
Detecting handler features...
Features determined
EV_KEY: 1
EV_KEY feature detected on /dev/input/event3
Done with handler at /dev/input/event3
Found handler at /dev/input/event2
Detecting handler features...
Features determined
EV_KEY: 1
EV_KEY feature NOT detected on /dev/input/event1
Done with handler at /dev/input/event1
Found handler at /dev/input/event0
Detecting handler features...
Features determined
EV_KEY: 1
EV_KEY feature NOT detected on /dev/input/event0
Done with handler at /dev/input/event0
Finished creating handler list
Handler list re-sized
*** stack smashing detected ***: ./thinputtest terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7f0ef8658807]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x0)[0x7f0ef86587d0]
./thinputtest[0x400ac7]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:02 7215828                            /home/tim/Documents/Programming/C/clogger/thinputtest
00601000-00602000 r--p 00001000 08:02 7215828                            /home/tim/Documents/Programming/C/clogger/thinputtest
00602000-00603000 rw-p 00002000 08:02 7215828                            /home/tim/Documents/Programming/C/clogger/thinputtest
01b88000-01ba9000 rw-p 00000000 00:00 0                                  [heap]
7f0ef8338000-7f0ef834d000 r-xp 00000000 08:02 5247337                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0ef834d000-7f0ef854c000 ---p 00015000 08:02 5247337                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0ef854c000-7f0ef854d000 r--p 00014000 08:02 5247337                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0ef854d000-7f0ef854e000 rw-p 00015000 08:02 5247337                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0ef854e000-7f0ef8703000 r-xp 00000000 08:02 5247958                    /lib/x86_64-linux-gnu/libc-2.15.so
7f0ef8703000-7f0ef8902000 ---p 001b5000 08:02 5247958                    /lib/x86_64-linux-gnu/libc-2.15.so
7f0ef8902000-7f0ef8906000 r--p 001b4000 08:02 5247958                    /lib/x86_64-linux-gnu/libc-2.15.so
7f0ef8906000-7f0ef8908000 rw-p 001b8000 08:02 5247958                    /lib/x86_64-linux-gnu/libc-2.15.so
7f0ef8908000-7f0ef890d000 rw-p 00000000 00:00 0 
7f0ef890d000-7f0ef892f000 r-xp 00000000 08:02 5255999                    /lib/x86_64-linux-gnu/ld-2.15.so
7f0ef8b08000-7f0ef8b0b000 rw-p 00000000 00:00 0 
7f0ef8b2b000-7f0ef8b2f000 rw-p 00000000 00:00 0 
7f0ef8b2f000-7f0ef8b30000 r--p 00022000 08:02 5255999                    /lib/x86_64-linux-gnu/ld-2.15.so
7f0ef8b30000-7f0ef8b32000 rw-p 00023000 08:02 5255999                    /lib/x86_64-linux-gnu/ld-2.15.so
7fffbd9b4000-7fffbd9d5000 rw-p 00000000 00:00 0                          [stack]
7fffbd9ff000-7fffbda00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

これを理解するのを手伝ってくれてありがとう。アドバイスや批評を送っていただければ幸いです。

4

1 に答える 1

2

ioctlサイズが間違っています:

ioctl(fd, EVIOCGBIT(EV_KEY, EV_MAX), results);

その行を次のように変更します。

ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(results)), results);

' ÷8しかないのに埋めるバイトがあることresultsを伝えるEVIOCGBITことで、境界の外に間接的に書き込んでいるため、スタックが破棄されます。スタック破壊検出の仕組みにより、一度しか検出できません。EV_MAXEV_MAXreturn

納得してもらうために、drivers/input/evdev.cのコメントを見てください。

/*
 * Work around bugs in userspace programs that like to do
 * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
 * should be in bytes, not in bits.
 */
于 2013-01-11T07:10:14.470 に答える