var++ к байтовой переменной на ARM64
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.01.23 22:48
Оценка:
Перетаскиваю код с x86/x64 на ARM64, собирая toolset'ом от VS 2019 (14.29.30140). Там, где на писюковых процессорах все идеально, на ARM64 (под QEMU 7.2.0) падает на внутренней отладочной проверке фактической разрядности значения (служебная функция CRT RTC_Check_4_to_1). В этом месте постфиксный ++ применяется к байтовой (unsigned char) переменной, имеющей значение 0xFF:

; 2297 :           Buf [i] = WData++;

    ldr         w8,[sp,#0x58]
    uxtw        x9,w8
    mov         x8,#1
    mul         x9,x9,x8
    ldr         x8,[sp,#0x18]
    add         x9,x8,x9
    ldrb        w8,[sp,#0x49]
    strb        w8,[x9]
    ldrb        w8,[sp,#0x49]
    add         w0,w8,#1
    mov         w0,w0
    bl          _RTC_Check_4_to_1
    uxtb        w8,w0
    mov         w8,w8
    mov         w8,w8
    strb        w8,[sp,#0x49]


Перед вызовом RTC_Check_4_to_1 w0/x0 имеют значение 0x100.

Компилятор делает неправильный код (по идее, должно быть явное обрезание после инкремента)? Или такое поведение возможно на некоторых архитектурах при применении ++ к байтовой переменной?
Re: var++ к байтовой переменной на ARM64
От: koenjihyakkei Россия  
Дата: 12.01.23 22:59
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

Возможно ub sanitizer включен (или какие в VS есть санитайзеры), он как раз примерно такие проверки вставляет.
Re[2]: var++ к байтовой переменной на ARM64
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.01.23 23:11
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Возможно ub sanitizer включен (или какие в VS есть санитайзеры)


Не "возможно", а точно включен (/RTCcsu). Вопрос в том, насколько эта конструкция корректна в смысле языка. В итоге в переменную записывается, как положено, байт (значение 0). Но функция проверки фактической разрядности значения вызывается для значения 0x100, полученного инкрементом 0xff, но не байтовой разрядности, а большей (какая там разрядность у w0/x0 — я с ARM почти не знаком).

Есть ли у ++ возможный UB при применении к байтовой переменной?
Re[3]: var++ к байтовой переменной на ARM64
От: koenjihyakkei Россия  
Дата: 12.01.23 23:32
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Не "возможно", а точно включен (/RTCcsu). Вопрос в том, насколько эта конструкция корректна в смысле языка. В итоге в переменную записывается, как положено, байт (значение 0). Но функция проверки фактической разрядности значения вызывается для значения 0x100, полученного инкрементом 0xff, но не байтовой разрядности, а большей (какая там разрядность у w0/x0 — я с ARM почти не знаком).


ЕМ>Есть ли у ++ возможный UB при применении к байтовой переменной?


Там после проверки 0х100 обрезается до 0 инструкцией uxtb. Если тип WData unsigned char, то проверка не должна вставляться, переполнение unsigned это не UB. Похоже на косяк санитайзера.
Re[3]: var++ к байтовой переменной на ARM64
От: night beast СССР  
Дата: 13.01.23 06:20
Оценка: 16 (1)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Есть ли у ++ возможный UB при применении к байтовой переменной?


C99 6.2.5/9

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.


для байтов исключение не делается.
Re[3]: var++ к байтовой переменной на ARM64
От: σ  
Дата: 13.01.23 08:55
Оценка:
ЕМ>Вопрос в том, насколько эта конструкция корректна в смысле языка. В итоге в переменную записывается, как положено, байт (значение 0). Но функция проверки фактической разрядности значения вызывается для значения 0x100, полученного инкрементом 0xff, но не байтовой разрядности, а большей (какая там разрядность у w0/x0 — я с ARM почти не знаком).

ЕМ>Есть ли у ++ возможный UB при применении к байтовой переменной?


C99 / 6.3 Conversions / 6.3.1 Arithmetic operands / 6.3.1.3 Signed and unsigned integers
> 2 if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
> 3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
Re[4]: var++ к байтовой переменной на ARM64
От: night beast СССР  
Дата: 13.01.23 09:09
Оценка:
Здравствуйте, σ, Вы писали:

ЕМ>>Есть ли у ++ возможный UB при применении к байтовой переменной?


σ>C99 / 6.3 Conversions / 6.3.1 Arithmetic operands / 6.3.1.3 Signed and unsigned integers


1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

Отредактировано 13.01.2023 9:09 night beast . Предыдущая версия .
Re[5]: var++ к байтовой переменной на ARM64
От: σ  
Дата: 13.01.23 09:15
Оценка:
NB>

1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.


И? В uchar = uchar + 1 отменили преобразование из int в unsigned char?
Re[6]: var++ к байтовой переменной на ARM64
От: night beast СССР  
Дата: 13.01.23 09:21
Оценка:
Здравствуйте, σ, Вы писали:

σ>И? В uchar = uchar + 1 отменили преобразование из int в unsigned char?


ты хочешь сказать что инкремент делает преобразование в инт а потом обрезает?
это где-то описано?
Отредактировано 13.01.2023 9:26 night beast . Предыдущая версия . Еще …
Отредактировано 13.01.2023 9:25 night beast . Предыдущая версия .
Re[7]: var++ к байтовой переменной на ARM64
От: σ  
Дата: 13.01.23 09:25
Оценка: 8 (1)
σ>>И? В uchar = uchar + 1 отменили преобразование из int в unsigned char?

NB>ты хочешь сказать что инкремент делает преобразование в инт а потом обрезает?

NB>это где-то описано?

Я думаю это оно
C99 6.5.2.4 Postfix increment and decrement operators

2 … See the discussions of additive operators and compound assignment for information on constraints, types, and conversions …

Отредактировано 13.01.2023 13:10 σ . Предыдущая версия .
Re: var++ к байтовой переменной на ARM64
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.01.23 09:31
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Перетаскиваю код с x86/x64 на ARM64, собирая toolset'ом от VS 2019 (14.29.30140). Там, где на писюковых процессорах все идеально, на ARM64 (под QEMU 7.2.0) падает на внутренней отладочной проверке фактической разрядности значения (служебная функция CRT RTC_Check_4_to_1). В этом месте постфиксный ++ применяется к байтовой (unsigned char) переменной, имеющей значение 0xFF:


1. Сгенерированный код какой-то наркоманский — что за умножение на 1? Вообще все оптимизации выключены?

ЕМ>; 2297 : Buf [i] = WData++;


ЕМ> ldr w8,[sp,#0x58]

ЕМ> uxtw x9,w8
ЕМ> mov x8,#1
ЕМ> mul x9,x9,x8

вот это. Я так понимаю, прочли i и "проиндексировали" для массива с элементом размером 1.

ЕМ> ldr x8,[sp,#0x18]

ЕМ> add x9,x8,x9

А это вычислили адрес элемента в Buf?

ЕМ> ldrb w8,[sp,#0x49]

ЕМ> strb w8,[x9]

Сохранили старое Wdata в массив. Теперь идём к постинкременту.

ЕМ> ldrb w8,[sp,#0x49]

ЕМ> add w0,w8,#1
ЕМ> mov w0,w0



ЕМ> bl _RTC_Check_4_to_1

ЕМ> uxtb w8,w0
ЕМ> mov w8,w8
ЕМ> mov w8,w8
ЕМ> strb w8,[sp,#0x49]

ЕМ>Перед вызовом RTC_Check_4_to_1 w0/x0 имеют значение 0x100.


ЕМ>Компилятор делает неправильный код (по идее, должно быть явное обрезание после инкремента)? Или такое поведение возможно на некоторых архитектурах при применении ++ к байтовой переменной?


А при чём тут архитектура?
Основной вопрос в том, как понимать усечение переменной при конверсии int -> uint8_t (unsigned char).
Тут вопрос скорее к пониманию стандарта и как его пытается понять компилятор.
Если бы это было чистое unsigned, то стандарт требовал modulo-арифметику и проверять нечего.
Но авторасширение до int создаёт другую логику — и я её плохо понимаю.
Кажется, она там implementation-defined, что происходит по умолчанию при таком усечении.
Тогда вопрос именно к компилятору — или к тому, как ему объяснить, что он неправ.

Прости, а нормальный компилятор (типа GCC, Clang) нельзя применить?
Потому что там всё это делается в духе

Buf[i] = Wdata;
__builtin_add_overflow(Wdata, 1, &Wdata); // если нужен truncating, переполнение гарантированно игнорировано


и тогда все санитайзеры всё равно правильно понимают, чего хотел кодер.
The God is real, unless declared integer.
Re[3]: var++ к байтовой переменной на ARM64
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.01.23 09:33
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Не "возможно", а точно включен (/RTCcsu). Вопрос в том, насколько эта конструкция корректна в смысле языка. В итоге в переменную записывается, как положено, байт (значение 0). Но функция проверки фактической разрядности значения вызывается для значения 0x100, полученного инкрементом 0xff, но не байтовой разрядности, а большей (какая там разрядность у w0/x0 — я с ARM почти не знаком).


wN — 32 бита.
xN — 64 бита.
N от 0 до 30 — стандартные регистры без странностей. 31 в зависимости от команды или SP, или пустой регистр (в котором всегда 0).

ЕМ>Есть ли у ++ возможный UB при применении к байтовой переменной?


Undefined, unspecified — насколько помню, нет.
Implementation defined — на обратном сжатии из int в байтовое значение.
The God is real, unless declared integer.
Re[2]: var++ к байтовой переменной на ARM64
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 13.01.23 14:21
Оценка:
Здравствуйте, netch80, Вы писали:

N>Вообще все оптимизации выключены?


Да, это отладочная сборка. Отключены все оптимизации и включены все проверки.

N>А при чём тут архитектура?


Вдруг там какой implementation-dependent behavior. Я мало знаком с ARM. А в подобных тонких особенностях стандарта разбираться очень сложно, если не изучать все это предметно.

N>Основной вопрос в том, как понимать усечение переменной при конверсии int -> uint8_t (unsigned char).


В том и вопрос, откуда там вообще int. Насколько я понимаю, здесь не должно быть расширения разрядности — по крайней мере, на уровне языка.

N>нормальный компилятор (типа GCC, Clang) нельзя применить?


Как будто в "нормальных компиляторах" не встречается подобных багов. Ну и собирается все это с Windows SDK/WDK, там есть ряд особенностей — не знаю, умеют ли GCC/Clang их все соблюдать.
Re: var++ к байтовой переменной на ARM64
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 17.01.23 10:49
Оценка: 13 (3)
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Перед вызовом RTC_Check_4_to_1 w0/x0 имеют значение 0x100.


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