Защитное программирование на C ++: чтение из буфера с безопасностью типов - PullRequest
1 голос
/ 01 сентября 2011

Допустим, у меня есть класс, который мне не принадлежит: DataBuffer. Предоставляет различные функции-члены get:

get(uint8_t *value);
get(uint16_t *value); 
...

При чтении из структуры, содержащейся в этом буфере, я знаю порядок и размер полей и хочу уменьшить вероятность будущих изменений кода, вызывающих ошибку:

struct Record 
{
    uint16_t Header;
    uint16_t Content;
}

void ReadIntoRecord(Record* r)
{
    DataBuffer buf( initialized from the network with bytes )
    buf.get(&r->Header); // Good!
    buf.get(&r->Content);
}

Затем кто-то проверяет изменения, чтобы что-то сделать с заголовком, прежде чем писать:

    uint8_t customHeader;
    buf.get(&customHeader);  // Wrong, stopped reading after only 1 byte
    r->Header = customHeader + 1;
    buf.get(&r->Content);  // now we're reading from the wrong part of the buffer.

Является ли следующий приемлемый способ защитить код от изменений? Помните, я не могу изменить имена функций на getByte, getUShort и т. Д. Я мог бы наследовать от DataBuffer, но это выглядит как избыточное.

    buf.get(static_cast<uint16_t*>(&r->Header));  // compiler will catch incorrect variable type
    buf.get(static_cast<uint16_t*>(&r->Content))

Обновлен на примере небезопасного устаревшего кода:

       float dummy_float;
        uint32_t dummy32;
        uint16_t dummy16;
        uint8_t dummy8;

        uint16_t headTypeTemp;
        buf.get(static_cast<uint16_t*>(&headTypeTemp));
        m_headType = HeadType(headTypeTemp);
        buf.get(static_cast<uint8_t*>(&hid));
        buf.get(m_Name);
        buf.get(m_SerialNumber);


        float start;
        buf.get(static_cast<float*>(&start));
        float stop;
        buf.get(static_cast<float*>(&stop));


        buf.get(static_cast<float*>(&dummy_float));
        setStuffA(dummy_float);

        buf.get(static_cast<uint16_t*>(&dummy16));
        setStuffB(float(dummy16)/1000);

        buf.get(static_cast<uint8_t*>(&dummy8));    //reserved





        buf.get(static_cast<uint32_t*>(&dummy32));
        Entries().setStart( dummy32 );
        buf.get(static_cast<uint32_t*>(&dummy32));
        Entries().setStop( dummy32 );
        buf.get(static_cast<float*>(&dummy_float));
        Entries().setMoreStuff( dummy_float );

        uint32_t datalength;
        buf.get(static_cast<uint32_t*>(&datalength));

        Entries().data().setLength(datalength);

        RetVal ret = ReturnCode::SUCCESS;
        Entry* data_ptr = Entries().data().data();
        for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
        {
            ret = buf.get(static_cast<float*>(&dummy_float));
            data_ptr[i].FieldA = dummy_float;
        }

        for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
        {
            ret = buf.get(static_cast<float*>(&dummy_float));
            data_ptr[i].FieldB = dummy_float;
        }

        // Read in the normalization vector
        Util::SimpleVector<float> norm;
        buf.get(static_cast<uint32_t*>(&datalength));
        norm.setLength(datalength);
        for (unsigned int i=0; i<datalength; i++)
        {
            norm[i] = buf.getFloat();
        }

        setNormalization(norm);

        return ReturnCode::SUCCESS;
}

Ответы [ 3 ]

1 голос
/ 01 сентября 2011

не лучше ли прочитать всю структуру из сети? Разрешение пользователю выполнять все операции с сокетами кажется мне плохой идеей (не инкапсулированной). Инкапсулируйте материал, который вы хотите отправить по сети, для работы с файловыми дескрипторами вместо того, чтобы позволить пользователю помещать необработанные данные буфера в файловые дескрипторы.

Я могу представить что-то вроде

void readHeader(int filedes, struct Record * Header);

так что вы можете сделать что-то вроде этого

struct Record 
{
  uint16_t Header;
  uint16_t Content;
  uint16_t getHeader() const { return Header; }
  uint16_t getContent() const  { return Content; }  
};

/* socket stuff to get filedes */
struct Record x;
readHeader(fd, &x);
x.getContent();
1 голос
/ 01 сентября 2011

Не используйте перегрузки.Почему бы не звонить get_word и get_dword?Интерфейс не будет более уродливым, но, по крайней мере, ошибку сделать намного сложнее.

0 голосов
/ 01 сентября 2011

Вы не можете читать из буфера с типом безопасности, если буфер не содержит информацию о содержимом. Один простой метод - добавить длину к каждой структуре и убедиться, что по крайней мере считываемые данные все еще имеют нормальную длину. Вы также можете использовать XML или ASN.1 или что-то подобное, когда предоставляется информация о типе. Конечно, я предполагаю, что вы также пишете в этот буфер.

...