Я заметил некоторую потенциальную проблему с макросом va_arg
, который используется для получения неназванного параметра из переменной функции. Рассмотрим следующий упрощенный пример:Сопоставляет ли const invism UB, когда аргумент указателя получен va_arg?
#include <stdio.h>
#include <stdarg.h>
void foo(int n, ...)
{
va_list ap;
const char *s;
va_start(ap, n);
for (s = va_arg(ap, const char *); *s != '\0'; s++)
putchar(*s);
va_end(ap);
}
int main(void)
{
char str[] = "xyz";
foo(1, str);
return 0;
}
Ссылка для va_arg
макро состояний, (курсив мой):
Если va_arg вызывается, когда нет больше аргументов в ар, или если тип следующий аргумент в ар (после продвижения по службе) не совместим с T, поведение не определено (...)
Мой U nderstanding является то, что const char *
и char *
типов не совместим. Когда char
массив передается в foo
в виде char
указателя (т.е. без изменений по умолчанию аргумент поощрений), то выражение, которое принимает константный квалифицированный указатель:
s = va_arg(ap, const char *)
может ссылаться на «технический» UB. Такая же ситуация возникла бы, когда arr
определяется как массив const
, и аргумент получен как char *
, а также для других типов, например. int *
и const int *
.
В этом случае несовместимость является проблемой размера, а не проблемой 'const'. когда размер неправильный, вы меняете сканирование va_args, и он сильно падает. Если бы он один раз пропустил 0 вместо 'NULL' на 64-битной машине. –