dereferencing pointer ... does break strict-aliasing rules
От: Klirik  
Дата: 14.07.10 01:29
Оценка:
Есть вот такой фрагмент:

template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
{
    *(T*)pPtr = tVal;
}

При его компиляции (gcc 4.4.3) всякий раз выскакивает упомянутое в теме топика предупреждение.

Как его победить?

Пробовал вот так:
template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
{
    union {
        void *pVoid;
        T *pT;
    } u;

    u.pVoid = pPtr;
    *u.pT = tVal;

}

— не помогает. Выскакивает то же самое предупреждение, но уже на строчку *u.pT = tVal.

Если сделать внутри вот так:
    u.pT = NULL;
    u.pVoid = pPtr;
    *u.pT = tVal;

— ситуация не меняется. Однако если при этом закомментировать вторую строку, вот так:
    u.pT = NULL;
    //u.pVoid = pPtr;
    *u.pT = tVal;

— то предупреждение исчезает (однако очевидно, что и смысла в таком коде нет. Разве что загадить системный лог сегфолтами).

ЗЫ: предупреждение по факту возникает в проекте при инстанциировании шаблона с T = int или uint.
Re: dereferencing pointer ... does break strict-aliasing rul
От: Serg27  
Дата: 14.07.10 03:39
Оценка:
Здравствуйте, Klirik, Вы писали:

K>Есть вот такой фрагмент:


...
K>Как его победить?

Это предупреждение имеет смысл. Дело в том, что не на всех архитекторах процессора это можно делать. Например может быть условие, что переменная типа int может лежать только по выровненному адресу (ну например адрес должен делиться на 4 без остатка). Т.е если у вас pPtr == 1025, то при выполнении Вашей функции с типом int произойдет аппаратное прерывание и программа вылетит .
Если Вы уверены, что у Вас этого нет (например работаете только на x86 процессорах), то просто запретите это предупреждение .
Re[2]: dereferencing pointer ... does break strict-aliasing
От: Klirik  
Дата: 14.07.10 04:44
Оценка:
Если обратили внимание на сам пример — там достаточно недвусмысленное название функции .

S>Если Вы уверены, что у Вас этого нет (например работаете только на x86 процессорах), то просто запретите это предупреждение .


Эта версия используется только на тех архитектурах, где выравнивание неважно. На тех, где возможно исключение, используется другой код.
Тем не менее — "просто запретить" — тоже далеко не всегда вариант. Например, если вы делаете пакет для gentoo с усиленной политикой, где при наличии подобного варнинга он просто не будет установлен в систему, либо будет считаться ненадёжным.

Мне хочется найти не обходное, а действительное решение этой проблемы.
Re[3]: dereferencing pointer ... does break strict-aliasing
От: Serg27  
Дата: 14.07.10 05:33
Оценка:
Здравствуйте, Klirik, Вы писали:

K>Если обратили внимание на сам пример — там достаточно недвусмысленное название функции .

Ну мало ли, может Вы не знаете что такое выравнивание Прошу прощения за ликбез.

S>>Если Вы уверены, что у Вас этого нет (например работаете только на x86 процессорах), то просто запретите это предупреждение .


K>Эта версия используется только на тех архитектурах, где выравнивание неважно. На тех, где возможно исключение, используется другой код.

K>Тем не менее — "просто запретить" — тоже далеко не всегда вариант. Например, если вы делаете пакет для gentoo с усиленной политикой, где при наличии подобного варнинга он просто не будет установлен в систему, либо будет считаться ненадёжным.

По моему проблем нет:
K>Эта версия используется только на тех архитектурах, где выравнивание неважно. На тех, где возможно исключение, используется другой код.
используйте везде этот "другой код".

Если этот код используется только на "архитектурах, где выравнивание неважно", то значит стоят всякие #ifdef. Ну и добавьте туда еще
#pragma warning( push)
#pragma warning( disable : ???)
// код функции
#pragma warning( pop )

Пример для VC++, gcc давно не использовал.

K>Мне хочется найти не обходное, а действительное решение этой проблемы.


Вы бы объяснили что именно хотите. Так как на уровне этой функции это предупреждение компилятора совершенно по делу. Т.е. решение нужно искать на уровень выше. Или все же плюнуть на предупреждение, но добавив защиту (assert, static_assert, #ifdef и т.п.)
Re: dereferencing pointer ... does break strict-aliasing rul
От: remark Россия http://www.1024cores.net/
Дата: 14.07.10 06:38
Оценка: +1
Здравствуйте, Klirik, Вы писали:

K>
K>template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
K>{
K>    *(T*)pPtr = tVal;
K>}
K>

K>При его компиляции (gcc 4.4.3) всякий раз выскакивает упомянутое в теме топика предупреждение.

Мне кажется так должно быть нормально:
template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
{
  memcpy(pPtr, &tVal, sizeof(tVal));
}



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: dereferencing pointer ... does break strict-aliasing rul
От: uzhas Ниоткуда  
Дата: 14.07.10 06:50
Оценка:
Здравствуйте, Klirik, Вы писали:

K>Есть вот такой фрагмент:


Есть вот такой топик: http://rsdn.ru/forum/cpp/3876328.flat.aspx
Автор: placement_new
Дата: 13.07.10
Re: dereferencing pointer ... does break strict-aliasing rul
От: uzhas Ниоткуда  
Дата: 14.07.10 07:17
Оценка: 1 (1)
Здравствуйте, Klirik, Вы писали:
Почему выскакивает предупреждение? Потому что что-то может пойти не так.
Вот гугл http://stackoverflow.com/questions/2771023/c99-strict-aliasing-rules-in-c-gcc
А вот стандарт:

3.10 Lvalues and rvalues
15. If a program attempts to access the stored value of an object through an lvalue of other than one of the following
types the behavior is undefined 48):

__________________
48) The intent of this list is to specify those circumstances in which an object may or may not be aliased.

А вот что стандарт разрешает:

3.9 Types
For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid
value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or
unsigned char.36) If the content of the array of char or unsigned char is copied back into the
object, the object shall subsequently hold its original value. [Example:
#define N sizeof(T)
char buf[N];
T obj; // obj initialized to its original value
memcpy(buf, &obj, N); // between these two calls to memcpy,
// obj might be modified
memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type
// holds its original value
—end example]

соглашусь, что всё это мутно
под алиасингом я понимаю синонимы для объектов и когда вы спускаетесь до void*, компилятор теряется и не знает, что вы через этот указатель можете изменить\прочитать. это заставляет его отказаться от некоторых типов оптимизаций. надо работать в типизированном мире и как можно реже спускаться до char*, void*, тогда компилятору будет легче
Re[2]: dereferencing pointer ... does break strict-aliasing
От: Serg27  
Дата: 14.07.10 08:06
Оценка: +1
Здравствуйте, remark, Вы писали:


R>Мне кажется так должно быть нормально:

R>
R>template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
R>{
R>  memcpy(pPtr, &tVal, sizeof(tVal));
R>}
R>

это нормально, если побайтное копирование даст тот же результат, что и выполнение оператора присваивания. Это будет верно не для всех типов T.
Что именно имеется ввиду у ТС не понятно.
Хотя если судить по названию функции и стоит только задача убрать заботливое предупреждение от компилятора и использовать только на x86, то может быть и нормально.
Re[2]: dereferencing pointer ... does break strict-aliasing
От: Klirik  
Дата: 14.07.10 11:01
Оценка:
Здравствуйте, uzhas, Вы писали:

U>15. If a program attempts to access the stored value of an object through an lvalue of other than one of the following

U>types the behavior is undefined 48):

U>

Дело немного в другом.
Понятно, что оригинальный вариант ( *(T*)pPtr = tVal; ) с прямым преобразованием типов должен вызывать предупреждение об undefined behavior — как раз покуда void* не является типом объекта.
Мне непонятно, почему такая же проблема возникает с union, который вроде как раз должен победить ситуацию.

Напомню:
template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
{
    union {
        void *pVoid;
        T *pT;
    } u;

    u.pVoid = pPtr;
    *u.pT = tVal;
}


Здесь ровно тоже предупреждение почему-то возникает на строчке *u.pT = tVal; Хотя здесь нет вообще ни одного приведения типов.
Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.
И — опять же, я уже упоминал — если убрать инициализацию u.pVoid = pPtr строчкой выше, то это предупреждение исчезает.
Вопрос — каким образом u.pVoid влияет на поведение компилятора по отношению к u.pT?

Ещё раз, иначе:
есть int *pInt, a. Разве присваивание *pInt = a может вызывать ошибку алиасинга? Всё же типизировано!
А если так — то какое дело, компилятору что int *pInt является членом какого-то union?

Под приведённую выше цитату из Стандарта не попадает только то, что членом union является не сам тип, а указатель на него.
Re[3]: dereferencing pointer ... does break strict-aliasing
От: dilmah США  
Дата: 14.07.10 11:09
Оценка:
K>Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.

а почему просто не добавить -fno-strict-aliasing к опциям gcc?
Re[3]: dereferencing pointer ... does break strict-aliasing
От: SleepyDrago Украина  
Дата: 14.07.10 11:28
Оценка: 17 (2)
Здравствуйте, Klirik, Вы писали:
...
K>Дело немного в другом.
K>Понятно, что оригинальный вариант ( *(T*)pPtr = tVal; ) с прямым преобразованием типов должен вызывать предупреждение об undefined behavior — как раз покуда void* не является типом объекта.
K>Мне непонятно, почему такая же проблема возникает с union, который вроде как раз должен победить ситуацию.
...
K>Здесь ровно тоже предупреждение почему-то возникает на строчке *u.pT = tVal; Хотя здесь нет вообще ни одного приведения типов.
здесь есть попытка передачи информации _между_ типами. Это и конфликтует со strict aliasing. Единственное послабление — работа через unsigned char* причем мееедленно а ля memcpy руками.

K>Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.

ему практически положить на выравнивания. Подумаешь программа всхлипнет "bus error" и склеит ласты — выравнивания гцц особо не волнуют.

...
K>А если так — то какое дело, компилятору что int *pInt является членом какого-то union?
потому что оптимизатор имеет право считать запись T* и чтение int* (и наоборот) не пересекающимися и выбросить вообще если то что было записано как int* не читается как int*.

есть классическая дока по strict aliasing от Mike Acton пожалуйста почитайте — а то стандарты пишут буквоеды для буквоедов там трудно это воспринимать.
Re[4]: dereferencing pointer ... does break strict-aliasing
От: Klirik  
Дата: 14.07.10 12:20
Оценка:
Здравствуйте, SleepyDrago, Вы писали:

SD>есть классическая дока по strict aliasing от Mike Acton пожалуйста почитайте — а то стандарты пишут буквоеды для буквоедов там трудно это воспринимать.


Вот за это спасибо
В разделе "Casting through a union (2)" как раз нашёл подобный случай с упоминанием warning-а gcc как false positive. Похоже, это оно и есть. Придётся, видимо, в это конкретное место лепить какую-нибудь прагму
Re[4]: dereferencing pointer ... does break strict-aliasing
От: Klirik  
Дата: 14.07.10 12:24
Оценка:
Здравствуйте, dilmah, Вы писали:


K>>Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.


D>а почему просто не добавить -fno-strict-aliasing к опциям gcc?


Проект немаленький, к тому же собирается под разные платформы (и под те, где unaligned-копирование объектов возможно только как блобов (т.е. через memcpy)). В целом такие ситуации компилятор хорошо замечает, и не хотелось бы просто избавляться от "надоедливых" напоминаний, но разобраться, почему они возникают.

К тому же — (я уже упоминал) — в некоторых случаях (усиленный gentoo) сборка такого проекта всё равно выкусит из опций -fno-strict-aliasing, а потом громко ругнётся в конце на "poor programming practice" и посчитает весь пакет в целом ненадёжным, а то и вообще откажется устанавливать его из-за этого в систему.
Re[5]: dereferencing pointer ... does break strict-aliasing
От: uzhas Ниоткуда  
Дата: 14.07.10 12:43
Оценка:
Здравствуйте, Klirik, Вы писали:

K>В разделе "Casting through a union (2)" как раз нашёл подобный случай с упоминанием warning-а gcc как false positive. Похоже, это оно и есть.


ваш случай я бы отнес к "Casting through a union (3)"

Occasionally a programmer may encounter the following INVALID method for creating an alias with a pointer of a different type:
0 typedef union
1 {
2 uint16_t* sp;
3 uint32_t* wp;
4 } U32P;

Re: dereferencing pointer ... does break strict-aliasing rul
От: Ops Россия  
Дата: 15.07.10 15:52
Оценка:
А C++-style casting не пробовали?

    *reinterpret_cast<T*>(pPtr) = tVal;
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[3]: dereferencing pointer ... does break strict-aliasing
От: March_rabbit  
Дата: 16.07.10 09:19
Оценка:
Здравствуйте, Klirik, Вы писали:

K>Мне хочется найти не обходное, а действительное решение этой проблемы.

если Вам нужно на самом деле взять 4-х байтовый int из произвольного места "правильным способом", то читайте его байтами.
Re: dereferencing pointer ... does break strict-aliasing rul
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 16.07.10 11:38
Оценка: :)
Здравствуйте, Klirik, Вы писали:

K>Есть вот такой фрагмент:


K>
K>template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
K>{
K>    *(T*)pPtr = tVal;
K>}
K>


K>ЗЫ: предупреждение по факту возникает в проекте при инстанциировании шаблона с T = int или uint.

почему-то мне хочется сделать вот так

template < typename T, typename U > void UnalignedWrite ( U * pPtr, const T & tVal )
{
    (reinterpret_cast<T&> (*pPtr)) = tVal;
}
Sic luceat lux!
Re[2]: dereferencing pointer ... does break strict-aliasing
От: Klirik  
Дата: 19.07.10 10:12
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>А C++-style casting не пробовали?


Ops>
Ops>    *reinterpret_cast<T*>(pPtr) = tVal;
Ops>


Пробовал. Стиль здесь неважен; результат тот же.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.