1

古いPowerPCに接続されたカスタムハードウェア用のキャラクターデバイスドライバーのIOCTLを作成しているときに、奇妙な問題を見つけました。これが私のコードの抽象化です:

u32 mydev_data;

...

static long mydev_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
    void __user *user_arg = (void __user *)arg;
    long result;

    switch(cmd) {

    case MYDEV_GETDATA:
        result = put_user(mydev_data, user_arg);
        break;

    ...
    }

    return result;
}

さて、これはゴミを返します。ただし、回線を入れ替えると

result = put_user(mydev_data, user_arg);

result = put_user(mydev_data, (unsigned long __user *) user_arg);

問題はなくなります。

ここで何が起こっているのですか?user_argは__user*としてマークされているため、唯一の違いはvoidとunsignedlongです。しかし、ここではポインタの種類は重要ではないと思います。明らかに私は間違っていますが、誰かが理由を説明できますか?

4

1 に答える 1

2

マクロの定義を見るとput_user、サイズに基づいてデータをsizeof(*ptr)コピーし、コピーするバイト数を決定していることがわかります。sizeof(void) == 1、しかしsizeof(unsigned long)大きいです。

#define __put_user_check(x, ptr, size)                                  \
({                                                                      \
        long __pu_err = -EFAULT;                                        \
        __typeof__(*(ptr)) __user *__pu_addr = (ptr);                   \
        might_sleep();                                                  \
        if (access_ok(VERIFY_WRITE, __pu_addr, size))                   \
                __put_user_size((x), __pu_addr, (size), __pu_err);      \
        __pu_err;                                                       \
})

#define put_user(x, ptr) \
  __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
于 2013-02-06T17:50:48.863 に答える