#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.
Комментариев нет:
Отправить комментарий