【问题标题】:Kernel Device Driver "dereferencing 'void *' pointer内核设备驱动程序“取消引用'void *'指针
【发布时间】:2011-02-18 22:46:34
【问题描述】:

我正在学习如何为 linux 编写设备驱动程序,我有一个关于使用通用数据结构的问题。

我有一个任务,我有完整的功能......所以我不要求你做我的家庭作业......

此分配要求设备能够将元素从 fifo 缓冲区中入队和出队。我使缓冲区“通用”,以便可以使用任何元素大小(并在运行时指定)。源码在下面(注意这不是内核版本,但错误是一样的)...内核版本需要kmalloc、copy_to/from_user()等...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct RB_Buffer
{
    void* RBData;
    unsigned int getindex;  //index to remove element
    unsigned int putindex;  //index to put element at
    unsigned int capacity;  //max elements buffer holds
    unsigned int elemCount; //num elements inserted
    unsigned int elemSize;  //size of each element
};

void* RB_kcreate(int numElements, unsigned int elementSize);
int putring(struct RB_Buffer *rbptr, void* data);
int getring(struct RB_Buffer *rbptr, void* data);


//Creates a Ring buffer of specified number of elements and element size.
//Returns void* pointer pointing to the RB_Buffer struct. This pointer can
//then be used on putring and getring functions.
void* RB_kcreate(int numElements, unsigned int elementSize)
{
    struct RB_Buffer *newBuf = malloc(sizeof(struct RB_Buffer));
    if(newBuf == NULL) return 0;
    newBuf->RBData = (void*)malloc(elementSize*numElements);//, GFP_KERNEL);
    if(newBuf->RBData == NULL)
    {
        free(newBuf);
        return 0;
    }
    newBuf->capacity = numElements;
    newBuf->elemSize = elementSize;
        newBuf->getindex = 0;
        newBuf->putindex = 0;
        newBuf->elemCount = 0;

    return newBuf;
}

//puts an element in the buffer. Returns -1 if full, 0 on success
//send data through void* data argument
int putring(struct RB_Buffer *rbptr, void* data)
{
    int i = 0;
    if ( rbptr->elemCount >= rbptr->capacity )
        return -1;

    memcpy(&rbptr->RBData[rbptr->putindex * rbptr->elemSize], data, rbptr->elemSize);
    rbptr->putindex++;
    if (rbptr->putindex >= rbptr->capacity )
        rbptr->putindex = 0;
    rbptr->elemCount++;

    return 0;
}

//removes an element in the buffer. Returns -1 if empty, 0 on success
//data is returned through the data pointer
int getring(struct RB_Buffer *rbptr, void *data)
{
    if ( !rbptr->elemCount )
        return -1;


    rbptr->elemCount--;
    memcpy(data, &rbptr->RBData[rbptr->getindex * rbptr->elemSize], rbptr->elemSize);
    rbptr->getindex++;
    if ( rbptr->getindex >= rbptr->capacity )
        rbptr->getindex = 0;

    return 0;

}

当我将它编译成内核模块时,我收到警告:

kringbuf_generic.c:53: warning: dereferencing ‘void *’ pointer kringbuf_generic.c:72: warning: dereferencing ‘void *’ pointer

在putring(in memcpy)中出现错误

if ( rbptr->elemCount >= rbptr->capacity )
            return -1;

        memcpy(&rbptr->RBData[rbptr->putindex * rbptr->elemSize], data, rbptr->elemSize);
        rbptr->putindex++;

在 getring 中,在 memcpy() 函数中

rbptr->elemCount--;
        memcpy(data, &rbptr->RBData[rbptr->getindex * rbptr->elemSize], rbptr->elemSize);
        rbptr->getindex++;

显然,由于这是一个内核模块,所以不知道谁会使用它,并且固定缓冲区元素大小将限制此缓冲区的使用。

有什么办法可以消除这些警告吗?还是在开发此类代码时我应该做一些不同的基本事情?

【问题讨论】:

  • 抱歉,我不会数行数来确定哪一行是第 72 行。但是你不能用类型转换消除警告吗?
  • 如果你告诉我们错误发生在哪里会很好。我想这是 copy_to_user 行? copy_to_user 的第二个参数是什么?
  • 抱歉,已修复。将代码更改为任何人都可以使用的版本(非内核)。
  • 对不起,堆栈溢出的新手...不直观如何接受答案...
  • 嗯,一个大勾号,如果将鼠标悬停在它上面会有一个工具提示...对不起,我没有挖掘,欢迎并玩得开心...

标签: c pointers kernel driver void-pointers


【解决方案1】:

我认为问题在于这段代码:

rbptr->RBData[rbptr->getindex * rbptr->elemSize]

正在尝试索引RBData 指向的数组,该数组的类型为void *。您无法对 void* 指针有意义地进行此操作,因为在 C 中对数组进行索引需要您知道数组中元素的大小,并且根据定义,void* 是指向未知类型。

大多数编译器都允许您通过将void* 隐式转换为char* 并仅读取原始字节值来执行此操作。但是,这样做确实不是一个好主意,因为操作没有明确定义。

要解决此问题并消除警告,请考虑在取消引用之前将 RBData 字段显式类型转换为 char*

((char *)rbptr->RBData)[rbptr->getindex * rbptr->elemSize]

或者,也可以将其作为char* 存储在您的结构中,以避免重复进行这种类型转换。

希望这会有所帮助!

【讨论】:

  • 谢谢!这真的很有帮助。没有更多警告!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
相关资源
最近更新 更多