Я пытаюсь удалить предупреждения из блока кода. Он имеет эту функцию:
void OPN2_Reset(ym3438_t *chip, Bit32u rate, Bit32u clock)
{
Bit32u i, rateratio;
rateratio = (Bit32u)chip->rateratio;
memset(chip, 0, sizeof(ym3438_t));
...
Это генерирует предупреждение во время сборки:
In function ‘void* memset(void*, int, size_t)’,
inlined from ‘void Ym2612_NukedImpl::OPN2_Reset(ym3438_t*, Bit32u, Bit32u)’ at /home/logiclrd/zdoom/zmusic_build/zmusic/thirdparty/game-music-emu/gme/Ym2612_Nuked.cpp:1413:11,
inlined from ‘void Ym2612_Nuked_Emu::reset()’ at /home/logiclrd/zdoom/zmusic_build/zmusic/thirdparty/game-music-emu/gme/Ym2612_Nuked.cpp:1842:45:
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:59:33: warning: argument 1 null where non-null expected [-Wnonnull]
59 | return __builtin___memset_chk (__dest, __ch, __len,
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
60 | __glibc_objsize0 (__dest));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:59:33: note: in a call to built-in function ‘void* __builtin_memset(void*, int, long unsigned int)’
Я перепробовал кучу поисков, пытаясь понять, как сообщить компилятору, что chip
здесь нет, NULL
я пробовал разные вещи, и, похоже, ничего не работает.
// DOESN'T WORK
if (chip != NULL)
memset(chip, 0, sizeof(ym3438_t));
// DOESN'T WORK
ym3438_t tmp;
ym3438_t *chip_nonnull = &tmp;
if (chip != NULL)
chip_nonnull = chip;
memset(chip_nonnull, 0, sizeof(ym3438_t));
// DOESN'T WORK
assert(chip != NULL);
memset(chip, 0, sizeof(ym3438_t));
Как мне вызвать на memset
только тогда, когда chip
не равно нулю, чтобы избежать этого предупреждения? Или как мне указать компилятору рассматривать chip
как ненулевое значение?
Похоже, что компилятор выполнил статический анализ, который показывает, что указатель действительно равен нулю. Вам нужно включить код, вызывающий эту функцию, чтобы увидеть, как это может быть.
Я попробую минимальный. Между тем, его можно тривиально воспроизвести (только не минимально) путем клонирования github.com:/ZDoom/ZMusic и его сборки (mkdir build ; cd build ; cmake .. ; make).
Один из способов — переключиться на использование ссылочного параметра вместо указателя. Это гарантирует, что у вас есть действительный объект для работы. Затем вы просто меняете вызов memset
на memset(&chip, 0, sizeof(ym3438_t));
.
Не имеет отношения к вашей проблеме, но каждый раз, когда вы чувствуете необходимость выполнить явное преобразование в стиле C (приведение, которое вы выполняете для задания rateratio
), вы должны воспринимать это как знак того, что вы, вероятно, делаете что-то неправильно.
@MarkRansom Почему выдается предупреждение даже в случае второго DOESN'T WORK
? В этом случае chip_nonnull
никогда не может быть NULL. Он инициализируется значением, отличным от NULL, а затем значение chip
копируется, только если оно не равно NULL.
Также обратите внимание, что в C++ символы NULL
— это макрос обратной совместимости C. Вместо этого используйте nullptr
.
@Someprogrammerdude Достаточно справедливо :-) Это сторонняя кодовая база, и я просто пытаюсь исключить предупреждения из сборки без особой личной выгоды.
Предупреждение, которое вы видите, не имеет ложных срабатываний в том смысле, что здесь нет эвристики. Если вы видите это, значит, где-то есть вызов вашей функции, который компилятор смог встроить/постоянно свернуть, чтобы указатель стал нулевым. Единственное, что может быть ложным срабатыванием, это то, что конкретный сайт вызова может фактически не оцениваться при выполнении программы (в этом случае предупреждения такого типа очень раздражают).
Хорошо, я вижу. В этом случае вы могли бы пока оставить это в покое, но я бы воспринял это как предупреждение о том, что стороннему разработчику может быть удобнее работать с C, чем с C++, и, следовательно, в коде C++ могут быть недостатки.
if ( !chip_r ) Ym2612_NukedImpl::OPN2_Reset( chip_r, ...
@DrewDormann Эй, отличный улов! Похоже на настоящий баг. Если бы мне пришлось угадывать, условие if
было бы неправильным. Мне кажется очень странным, что я все еще получаю предупреждение даже после второй попытки обхода, но если скрестить пальцы, перевернув if
, оно исчезнет.
@DrewDormann Да, это помогло. Если вы хотите, чтобы это был ответ, я приму его. Спасибо!
@DrewDormann отличная работа, я бы никогда не подумал, что исходный код общедоступен.
Спасибо, @MarkRansom. Этот сайт научил меня гуглить странные имена файлов.
Рассматриваемый указатель имеет значение null в 100% случаев из упомянутого стека вызовов.
if ( !chip_r ) Ym2612_NukedImpl::OPN2_Reset( chip_r, static_cast<Bit32u>(prev_sample_rate), static_cast<Bit32u>(prev_clock_rate) );
// ^^^^^^^ if it's null... pass it ^^^^^^
Я не понимаю, почему это все еще генерирует предупреждение: // ym3438_t tmp; ym3438_t *chip_nonnull = &tmp; [здесь определенно не NULL] if (chip)chip_nonnull = чип; [здесь не может стать NULL] memset(chip_nonnull, 0, sizeof(ym3438_t)); // Но это определенно настоящая причина и почти наверняка настоящая ошибка. Спасибо :-)
@JonathanGilbert Код в вопросе уже имеет неопределенное поведение из-за (Bit32u)chip->rateratio
в предыдущей строке. Если вы не удалите это или не заставите использовать chip_nonnull
, все ставки отменены.
Можете ли вы показать минимальный воспроизводимый пример , который выдает это предупреждение? Что-то, что любой из нас мог бы скомпилировать, чтобы увидеть то же предупреждение. Предупреждение, по-видимому, подразумевает, что gcc знает, что значение в строке 1413 файла Ym2612_Nuked.cpp равно нулю.