Как сообщить GCC, что указатель ненулевой?

Я пытаюсь удалить предупреждения из блока кода. Он имеет эту функцию:

 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 как ненулевое значение?

Похоже, что компилятор выполнил статический анализ, который показывает, что указатель действительно равен нулю. Вам нужно включить код, вызывающий эту функцию, чтобы увидеть, как это может быть.

Mark Ransom 06.09.2024 18:36

Я попробую минимальный. Между тем, его можно тривиально воспроизвести (только не минимально) путем клонирования github.com:/ZDoom/ZMusic и его сборки (mkdir build ; cd build ; cmake .. ; make).

Jonathan Gilbert 06.09.2024 18:36

Один из способов — переключиться на использование ссылочного параметра вместо указателя. Это гарантирует, что у вас есть действительный объект для работы. Затем вы просто меняете вызов memset на memset(&chip, 0, sizeof(ym3438_t));.

NathanOliver 06.09.2024 18:36

Не имеет отношения к вашей проблеме, но каждый раз, когда вы чувствуете необходимость выполнить явное преобразование в стиле C (приведение, которое вы выполняете для задания rateratio), вы должны воспринимать это как знак того, что вы, вероятно, делаете что-то неправильно.

Some programmer dude 06.09.2024 18:37

@MarkRansom Почему выдается предупреждение даже в случае второго DOESN'T WORK? В этом случае chip_nonnull никогда не может быть NULL. Он инициализируется значением, отличным от NULL, а затем значение chip копируется, только если оно не равно NULL.

Jonathan Gilbert 06.09.2024 18:37

Также обратите внимание, что в C++ символы NULL — это макрос обратной совместимости C. Вместо этого используйте nullptr.

Some programmer dude 06.09.2024 18:38

@Someprogrammerdude Достаточно справедливо :-) Это сторонняя кодовая база, и я просто пытаюсь исключить предупреждения из сборки без особой личной выгоды.

Jonathan Gilbert 06.09.2024 18:38

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

user17732522 06.09.2024 18:40

Хорошо, я вижу. В этом случае вы могли бы пока оставить это в покое, но я бы воспринял это как предупреждение о том, что стороннему разработчику может быть удобнее работать с C, чем с C++, и, следовательно, в коде C++ могут быть недостатки.

Some programmer dude 06.09.2024 18:40
мне кажется, что чип выглядит НУЛЕВЫМ. if ( !chip_r ) Ym2612_NukedImpl::OPN2_Reset( chip_r, ...
Drew Dormann 06.09.2024 18:41

@DrewDormann Эй, отличный улов! Похоже на настоящий баг. Если бы мне пришлось угадывать, условие if было бы неправильным. Мне кажется очень странным, что я все еще получаю предупреждение даже после второй попытки обхода, но если скрестить пальцы, перевернув if, оно исчезнет.

Jonathan Gilbert 06.09.2024 18:43

@DrewDormann Да, это помогло. Если вы хотите, чтобы это был ответ, я приму его. Спасибо!

Jonathan Gilbert 06.09.2024 18:46

@DrewDormann отличная работа, я бы никогда не подумал, что исходный код общедоступен.

Mark Ransom 06.09.2024 19:02

Спасибо, @MarkRansom. Этот сайт научил меня гуглить странные имена файлов.

Drew Dormann 06.09.2024 19:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
15
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Рассматриваемый указатель имеет значение 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)); // Но это определенно настоящая причина и почти наверняка настоящая ошибка. Спасибо :-)

Jonathan Gilbert 06.09.2024 19:12

@JonathanGilbert Код в вопросе уже имеет неопределенное поведение из-за (Bit32u)chip->rateratio в предыдущей строке. Если вы не удалите это или не заставите использовать chip_nonnull, все ставки отменены.

user17732522 06.09.2024 19:26

Другие вопросы по теме