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