Драйвер устройства ядра "разыменование указателя 'void *' - PullRequest
1 голос
/ 19 февраля 2011

Я учусь писать драйверы устройств для 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 (в 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++;

Очевидно, что поскольку это модуль ядра, на самом деле неизвестно, кто будет его использовать, и исправление размера элемента буфера ограничит использование этого буфера.

Есть ли способ избавиться от предупреждений? Или есть что-то фундаментальное, что я должен делать по-другому при разработке такого кода?

1 Ответ

4 голосов
/ 19 февраля 2011

Мне кажется, проблема в том, что этот код:

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

пытается индексировать массив, на который указывает RBData, который имеет тип void *.Вы не можете осмысленно заставить эту операцию работать с указателем void*, потому что для индексации массива в C требуется знать размер элементов в массиве, а по определению void* является указателем на элементынеизвестный тип.

Большинство компиляторов позволяют вам делать это в любом случае, неявно приводя void* к char* и просто читая необработанные байтовые значения.Тем не менее, это действительно плохая идея, так как операция не является четко определенной.

Чтобы исправить это и отключить предупреждение, рассмотрите возможность явного типизирования поля RBData до char* передразыменовываем его:

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

Или, в качестве альтернативы, просто сохраните его как char* в своей структуре, чтобы избежать необходимости повторять этот тип.

Надеюсь, это поможет!

...