Учитывая два указателя и длину для каждого из них, как я могу безопасно проверить, перекрывают ли эти области друг друга?
<
, <=
, >=
, >
не определены, если 2 указателя не связаны с одним и тем же объектом.
Утомительный подход проверяет конечные точки одного по отношению ко всем другим элементам и использует то, что длина источника и назначения одинакова .
int safe_memcpy(void *dest, const void *src, size_t length) {
if (length > 0) {
unsigned char *d = dest;
const unsigned char *s = src;
const unsigned char *s_last = s + length - 1;
for (size_t i = 0; i < length; i++) {
if (s == &d[i]) return 1; // not safe
if (s_last == &d[i]) return 1; // not safe
}
memcpy(dest, src, length);
}
return 0;
}
Если длины буферов различаются, проверьте конечные точки более коротких по адресам более длинных элементов.
должен ли я использовать все как char *
Используйте unsigned char *
. mem...()
, str...()
ведут себя так, как если бы каждый элемент массива был unsigned char
.
Для всех функций в этом подпункте каждый символ должен интерпретироваться так, как если бы он имел тип unsigned char
(и поэтому все возможные представления объекта действительны и имеют различное значение). C17dr § 7.24.1 3
С редкими дополнениями, отличными от 2, unsigned char
важно, чтобы избежать ловушек signed char
и сохранить -0, +0 различимость. Строки останавливаются только на + 0.
Для таких функций, как int strcmp/memcmp()
, unsigned char
, которые используют целочисленную математику, при сравнении элементов за пределами диапазона [0...CHAR_MAX]
важно возвращать результат с правильной подписью.
Даже если void *
индексация была разрешена, void *dest_end = &dest[length - 1];
очень плохо, когда length == 0
как это &dest[SIZE_MAX];
&src >= &dest
s / b src >= dest
даже для шанса на работу.
Адреса src, dest
не имеют отношения к копии, важны только их значения.
I подозреваю, что этот ошибочный код приводит к UB в другом коде OP.
Должен ли я вместо этого использовать intptr_t
или uintptr_t
?
Обратите внимание, что (u)intptr_t
являются необязательными типами - они могут не существовать в соответствующем компиляторе.
Даже если типы существуют, математика указателей не определена как связанная с математикой целочисленных значений.
Ясно, что эти адреса даже удаленно не перекрываются, поэтому я думаю, что запускаю UB,
«Ясно», если предполагает a адреса лайнера отображаются в целые числа, что не указано в C.