Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Язык C, переполнения указателя

#c #указатели #integer #overflow


1) Является ли переполнение указателя переполнением беззнакового целого? То есть,
валидно ли проверять факт переполнения после переполнения?

Например, по Стандарту переполнение знакового целого - это UB, из-за этого приходится
проверять возможное знаковое переполнение до того, как оно произойдет.

2) Является ли необходимой проверка переполнения указателя? 

Например, довольно часто возникает необходимость работать с данными через указатель
на массив, размер элемента и количество элементов.

Например, следующая ситуация однозначно нуждается в проверке того, что умножение
size на count не приведет к целочисленному переполнению типа size_t.

const void *const data = malloc(size * count);


Я подозреваю (но не уверен окончательно), что в проверке так же нуждается и следующая
ситуация с указателем:

void f(const uint8_t *const _data,
       const size_t _elem_on_record,
       const size_t _records_count)
{
    const size_t record_size = sizeof(uint8_t) * _elem_on_record;
    // Контроль возможного переполнения record_size.
    // ...

    for (size_t r = 0; r < _records_count; ++r)
    {
        const size_t bias = r * record_size;
        // Контроль возможного переполнения bias.
        // ...

        const uint8_t *const select_record = _data + bias;
        // Возможно переполнение select_record, даже если
        // переполнения bias не возникло...

        f2(record);
    }
}


Я понимаю, что за переполнение select_record несет ответственность тот, кто вызвал
функцию f1. Но я бы хотел защититься от ситуации, когда select_record оказывается переполнено.
Это актуально для безопасности, например, сервера.

Подскажите, действительно ли нужно контролировать возможное переполнение указателя,
и как это делать правильно?
    


Ответы

Ответ 1



В языке С нет и не может быть понятия "переполнения указателя". И, разумеется, никаким "целым" указатель не является. Арифметика и упорядочивающие сравнения указателей в С определены только в пределах элементов одного массива плюс воображаемый элемент, следующий за последним элементом этого массива. Попытка создания указателя, выходящие за пределы этого диапазона ведет к неопределенному поведению (произошло ли при этот какое-то "переполнение" или нет - роли не играет). В пределах же этого диапазона, разумеется, никакого "переполнения указателя" возникнуть не может: не может существовать массива, доступ к элементам которого вызывает какое-то адресное "переполнение", ибо сам доступ к элементам массива в С концептуально реализован через адресную арифметику указателей. Если вы работаете с массивом (блоком памяти), выделенным стандартными средствами языка, то ни о каком "переполнении указателей" вам беспокоиться не нужно.

Ответ 2



Указатель не является беззнаковым целым. Поддержка адресной арфиметики никак не гарантирует, что указатель есть целое. Как пример можно вспомнить адресацию в форме сегментный регистр + смещение в сегменте. Если уж вам так непременно нужно проверять валидность адресной арифметики, используйте функции IsBadReadPtr и IsBadWritePtr.

Комментариев нет:

Отправить комментарий