Комментарии 65
Не являюсь C++ программистом, но интересно, почему так?
CPU, в массе своей, имеют команды логического и арифметического сдвига. Репликация старшего бита осуществляется аппаратно.
Так что сдвиг int вправо работает на любом известном мне компиляторе, несмотря на то, что он отнесён к UB.
>> а при сдвиге влево нужно сдвигать все биты, кроме старшего.
Вы точно понимаете основы представления чисел в дополнительном коде?
-1 это 0xffffffff (для 32-битного числа). Ничего со старшим битом делать не надо.
Если же у вас происходит переполнение из 30 в 31 бит, то по-любому будет неверное число.
1824228096
-646511104
-1293022208
1708922880
-877121536
-1754243072
786481152
1572962304
-1149042688
1996881920
-301203456
-602406912
-1204813824
1885339648
-524288000
-1048576000
-2097152000
100663296
201326592
402653184
805306368
1610612736
-1073741824
-2147483648
Как видите, проблема не в том, что происходит «переполнение в старший бит». Ка краз наоборот! Происходит «недополнение». Т.е. 1 заменяется на 0. Если говорить о переполнении, то при сдвиге влево любого отрицательного числа старший выпадает. При сдвиге вправо реплицируется, как вы заметили, а при сдвиге влево замещается младшим битом.
Это вывод в MSVC2015-debug. Т.к. UB, то цифры могут быть другими в других условиях.
Его вы можете сдвинуть влево 7 раз без переполнений
>> «переполнение в старший бит». Ка краз наоборот! Происходит «недополнение».
Не нужно изобретать «недотермины».
Я тоже не знаю, но Яндекс утверждает, что это будет «потеря значимости». Google сильно неадекватнее: «изчезновение».
В любом случае, непонятно, при чём тут «underflow»: underflow будет когда вы (целое)3 разделите на (целое)2 и получите (целое)1, а не (с плавающей точкой)1,5.
Как представляет их микроконтроллер, это его дело, но (-1)<<1 (сдвиг без всякой логики) может превратиться в:
прямое) 1001 -> 0010 = 2,
сдвиг) 0111 -> 1110 = 6 (в 8-битной логике 126),
до 1) 1110 -> 1100 = -3,
до 2) 1111 -> 1110 = -2.
Скорей всего, дело в том, что крайний левый бит отвечает за знак. А побитовый сдвиг сдвигает все биты (в том числе и знаковый), и непонятно, что будет в этом крайнем бите после сдвига.
P.S. Я тоже не C++ программист, поэтому это лишь мои догадки
Так что даже так, не совсем понятно, почему поведение зовут «неопределенным».
What Every C Programmer Should Know About Undefined Behavior #1/3
Далее, опять же, на некоторых патформах некоторый набор бит в числе может быть так называемым trap representation, то есть вызывать хардварные исключения при появлении в вычислениях. Один из примеров — Signaling NaN.
Вместе эти два факта позволяют случится исключению, если сдвиг отрицательного числа порождает trap representation, и компилятору пришлось бы для такой платформы на каждый сдвиг вставлять код, поглощающий исключение.
Поскольку стандарты C и C++ писались «в пользу компилятора», то есть чтобы позволить максимальное число оптимизаций, они разрешают компилятору считать, что trap не произойдет и, значит, сдвига отрицательных чисел в программе нет.
В прошлой статье я нашёл одно ложное срабатывание, в этой
void CBuffer::Execute()
{
....
QuatT * pJointsTemp = static_cast<QuatT*>(
alloca(m_state.m_jointCount * sizeof(QuatT)));
....
}
потому что у QuantT
есть тривиальный пустой конструктор и нет деструктора, также класс не наследует другие классы, поэтому инициализацию можно и не выполнять.
Но я пока не знаю теорию статического анализа так хорошо, как авторы, поэтому не могу оценить объём работы, который требуется, чтобы проанализировать эти два случая правильно. Более того, формально второе предупреждение скорее всего верно, потому что использовать Си-инициализацию в С++ разрешено только для POD-типов, а QuantT
не подходит под это определение. И я не помню стандарт так хорошо, чтобы точно сказать, может ли быть UB при таком определении и при такой инициализации класса.
Я много таких людей встречал. Уезжая в другую страну, такие людей точно также будут сетовать на проблемы в этой стране.
ого!!! Вам не кажется, что это ОЧЕНЬ МНОГО ошибок для коммерческой разработки? (или для сипипей это норма?)
В тырнетах все такие умные — про тесты говорят, инверсии зависимостей, шаблоны, а тут проверили годами полируемый код — и такая лажа! Кого ж эти СлёзоТеки наняли, что на выходе имеют такое позорное качество?
Но коммент не ради этого, удивлят другое — как эта копипастная лапша вообще работала-то?? Вы все учили матрицы, 3D и всё такое — нельзя просто взять и вместо Z присвоить Y — получится такая белиберда, что её вообще на экране нельзя отображать! У них там что, на каждую индусофункцию ещё 10, которые исправляют баги первой? :)
PS
Для сипиписников с их ужасным инструментом, PVS — это must have за любые деньги!
Что до годами полируемого кода — очень смешно. Если бы это было так, у них бы была графика уровня 2003 года. А у них реальная гонка по скоростному освоению новых высот геймдева и, прежде всего, графена. И тут за право первым реализовать поддержку DX11 или VulkanAPI приносят в жертву не одного бычка, включая спагетти-код.
> сипиписников с их ужасным инструментом
А вот это про что было?
[Далее небольшой сеанс конструктивной (надеюсь) критики]
Скажите, а у вас есть доступ к native speaker'ам или хотя бы к учителям английского?
Мне кажется, это слишком похоже на «рунглиш со словарём»:
— «There is a probability of logical error presence.»
— «The '...' variable is assigned values twice successively.»
— «Member of a class is initialized by itself»
— «always returns one and the same value»
— «The memcmp function receives the pointer and its size as arguments.»
(аналогично вашей статье, выбрал только несколько ошибок для демонстрации, обращайтесь за полным отчётом :))
Я сам не носитель, но вышеперечисленные примеры вызывают у меня подозрения на правильность с точки зрения английского. Мне кажется, вам стоит нанять кого-нибудь, отлично знающего английский, и разбирающегося в программировании, чтобы разок-другой пройтись по списку ошибок, чтобы тулза, явно ориентированная в том числе на англоязычных пользователей, не носила ушанку и не говорила с русским акцентом [линк].
Keep up the good work!
Сколько предлагаете? :D
const float endTime = spawn.delay + HasDuration()? spawn.duration: fHUGE;
Так писать вообще плохая практика, неужели переменной отдельной жалко выделить под spawnDuration.
Собственно, при достижении указанного значения потребления памяти движок просто выдаёт ошибку выделения памяти(memory allocation for x bytes failed) по сей день на самой последней версии СЕ 5.1.1, прямо «из коробки», т.е без каких либо изменений кода и прочих элементов. На систему установлено 32 гигабайта оперативной памяти, в других движках, например «Юнити 5», подобных проблем с выделением памяти не наблюдалось. Память 100% остаётся свободна при возникновении ошибки, были протестированы конфигурации с 8ю и 16ю гигабайтами памяти, ошибка проявляется всегда при одинаковых условиях, появление ошибки так же не зависит от размера файла подкачки(при размере меньше 1го гб появляется похожая ошибка но уже с рекомендацией увеличить размер «heap» памяти).
Что меня конкретно интересует по результатам анализа: ошибки и спорные места в файлах GeneralMemoryHeap.h и cpp, MemoryFragmentationProfiler.h, MemoryAddressRange.h и cpp, MemoryManager.h и cpp, CryMemoryManager.cpp, CustomMemoryHeap.h и cpp, MTSafeAllocator.h и срр, PageMappingHeap.h и срр, CryDLMalloc.c, CrySizerImpl.h и срр, LevelHeap.cpp, MemReplay.h и срр а так же SystemWin32.cpp. Крайтек игнорирует сообщения об этой ошибке на своих форумах уже довольно давно, или в некоторых случаях просто не может сказать ничего вразумительного. Учитывая тот факт что за 10 лет проблема как была так и осталась то просто очевидно что фиксить они её не собираются в ближайшее время.
Данная проблема проявляет себя во всей красе при работе с большими уровнями, или уровнями с хорошей детализацией( в большом количестве мелкие объекты, инстанции растительности и пр.), всё это в совокупности может привести к заполнению движком 3.5 гб памяти с последующим возникновением ошибки выделения памяти. При тестировании такого уровня в дальнейшем в режиме игры проблем не возникает, т.к в режиме игры включаются определённые оптимизации и часть объектов просто не загружается в память полностью, тем не менее можно вызвать данную ошибку выделения даже во время игры заспавнив определённое количество объектов в любых местах уровня, при этом количество объектов не обязательно будет слишком большим, скажем 1700 объектов, что далеко от предела количества объектов на одном уровне обозначенного в офиц. документации.
Буду также очень рад если вы поделитесь своими идеями по поводу корней данной проблемы а так же возможных теоретических способах её решения. Вообще я стараюсь работать только с 2мя модулями движка — СryGame и CryAction и не лезть в другие модули, но моя надежда на то что Крайтек решит эту проблему в каком нибудь обновлении движка давно утрачена, а учитывая что теперь исходный код почти всех модулей доступен — почему бы не попробовать решить её?
Если речь о 64-битной версии, то скорее всего библиотека содержит классические 64-битные ошибки, о которых мы много писали. И тогда, когда память начинает выделяться за пределами младших 4 гигабайт, начинаются различные проблемы. Например, может разрушаться менеджер памяти и нехватка памяти это просто последствия его некорректной работы. На 64-битные ошибки мы код библиотеки не исследовали, так как для написания статьи нам хватило и предупреждений общего назначения. :)
Из описания не понятно, речь идёт о 32-битной или 64-битной версии библиотеки.Там вроде нормально написано:
Это наблюдается на любом железе с достаточным объёмом оперативной памяти и любой 64х разрядной ОС.
Не думаю, что человек, тестирующий на 32ГБ ОЗУ в течении 10 лет споткнётся о такую простую ошибку как несоответствие разрядности ОС и библиотеки.
почему бы не попробовать решить её?
Потому что подобные ошибки с памятью очень тяжело отлаживать. Даже программисту, который помнит свой код наизусть. А уж человеку, впервые увидевшему эти исходники, тем более нужно огромное количество времени, чтобы хоть как-то начать ориентироваться. И вообще, проблема может заключаться не только в движке, но и в каких-то сторонних библиотеках или даже в операционной системе (мало ли, какая программа из-за ошибки вышла за пределы своей памяти).
мало ли, какая программа из-за ошибки вышла за пределы своей памятиНа какой платформе, поддерживаемой CryEngine, это возможно, на приставках?
Долгожданная проверка CryEngine V