Если на моей платформе поддерживаются невыровненные загрузки, то почему очиститель адресов жалуется на неопределенное поC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Если на моей платформе поддерживаются невыровненные загрузки, то почему очиститель адресов жалуется на неопределенное по

Сообщение Anonymous »

Я использую библиотеку строк Stringzilla, которая должна быть близка к тому, как работает std::string. У него есть флаг SZ_USE_MISALIGNED_LOADS. По умолчанию он включен и выглядит это так:

Код: Выделить всё

/**
*  @brief  A misaligned load can be - trying to fetch eight consecutive bytes from an address
*          that is not divisible by eight. On x86 enabled by default. On ARM it's not.
*
*  Most platforms support it, but there is no industry standard way to check for those.
*  This value will mostly affect the performance of the serial (SWAR) backend.
*/
#ifndef SZ_USE_MISALIGNED_LOADS
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
#define SZ_USE_MISALIGNED_LOADS (1) // true or false
#else
#define SZ_USE_MISALIGNED_LOADS (0) // true or false
#endif
#endif
И так я понимаю, что на x86_64 (моя платформа) поддерживаются невыровненные нагрузки. Я включил UBSAN и получаю предупреждение о невыровненном чтении. Это когда я создаю строку с символом char*. Класс stringzilla создает строковое представление из моего char*, а затем выполняет:

Код: Выделить всё

void init(string_view other) noexcept(false)
{
// "other" is the string_view I passed in the constructor
sz_ptr_t start; // after allocating memory start = 0x7bfff5900029
if (!_with_alloc(
[&](sz_alloc_type &alloc) { return (start = sz_string_init_length(&string_, other.size(), &alloc)); }))

throw std::bad_alloc();
sz_copy(start, (sz_cptr_t)other.data(), other.size());
}
Тогда внутри sz_copy это выглядит так:

Код: Выделить всё

SZ_PUBLIC void sz_copy_serial(sz_ptr_t target, sz_cptr_t source, sz_size_t length) {
// The most typical implementation of `memcpy` suffers from Undefined Behavior:
//
//   for (char const *end = source + length; source < end; source++) *target++ = *source;
//
// As NULL pointer arithmetic is undefined for calls like `memcpy(NULL, NULL, 0)`.
// That's mitigated in C2y with the N3322 proposal, but our solution uses a design, that has no such issues.
// https://developers.redhat.com/articles/2024/12/11/making-memcpynull-null-0-well-defined
#if SZ_USE_MISALIGNED_LOADS
while (length >= 8) *(sz_u64_t *)target = *(sz_u64_t const *)source, target += 8, source += 8, length -= 8;
#endif
while (length--) *(target++) = *(source++);
}
Самый первый экземпляр, т.е.:

Код: Выделить всё

(*(sz_u64_t *)target = *(sz_u64_t const *)source
"target" имеет адрес, который, как я предполагаю, является результатом выделения: 0x7bfff5900029. УБСАН говорит здесь:

Код: Выделить всё

runtime error: store to misaligned address 0x7bfff5900029 for type 'sz_u64_t' (aka 'unsigned long'), which requires 8 byte alignment
Мои вопросы:
  • Если x86_64 поддерживает невыровненное чтение, и эта функция включена по умолчанию, почему UBSAN говорит, что это неопределенное поведение. Должен ли я отключить его вручную? Если я отключу его, копии в конечном итоге будут выполняться побайтно в цикле.
  • Почему выделение строки для хранения происходит даже по адресу 0x7bfff5900029? Это звучит как нелепый адрес с точки зрения выравнивания, полученный от функции распределения. Обычно они выравниваются по 8 или 16 байтам.
  • Эта пользовательская функция реализована потому, что memcpy(NULL) — это UB? Не лучше ли просто проверить NULL и использовать memcpy, который гарантированно будет намного лучше, чем любой ручной цикл?


Подробнее здесь: https://stackoverflow.com/questions/798 ... -sanitizer
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»