C - функция Variadic компилируется, но выдает ошибку сегментации
У меня есть переменная функция в C для записи в файл журнала, но как только она вызывается, она дает ошибку сегментации в заголовке.
В основном процессе вызов имеет следующий формат:
mqbLog("LOG_INFORMATION",0,0,"Connect",0,"","Parameter received");
и функция определяется следующим образом:
void mqbLog(char *type,
int numContext,
double sec,
char *service,
int sizeData,
char *data,
char *fmt,
...
)
{
//write the log in the archive
}
Это компилируется хорошо. Когда я отлаживаю процесс, вызов mqbLog
Функция выполнена, и она дает мне ошибку сегментации в открытой скобке функции, поэтому я могу спросить о значениях функции:
(gdb) p type
$1 = 0x40205e "LOG_INFORMATION"
(gdb) p numContext
$2 = 0
(gdb) p sec
$3 = 0
(gdb) p service
$4 = 0x0
(gdb) p sizeData
$5 = 4202649
(gdb) p data
$6 = 0x0
Любые идеи будут с благодарностью приняты.
1 ответ
Судя по выводу GDB, у вызывающей стороны не было прототипа для функции, которую он вызывал. Как заметил @JonathanLeffler, вы написали 0
вместо 0.0
, так что он передает целое число, где вызываемый ожидает double
,
Судя по значению указателя, это, вероятно, на Linux x86-64 с соглашением о вызовах System V, где регистр, назначенный для arg, определяется тем, что он является, например, третьим целочисленным arg. (См. Вики x86 для ABI/ документы соглашения о вызовах).
Поэтому, если вызывающая сторона и вызываемая сторона не согласны с сигнатурой функции, они не согласятся относительно того, какой аргумент входит в какой регистр, что, я думаю, объясняет, почему GDB показывает аргументы, которые не соответствуют вызывающей стороне.
В этом случае звонящий ставит "Connect"
(адрес) в RCX, потому что это 4-е целое число / указатель arg с этим неявным объявлением.
Звонящий ищет значение service
в RDX, потому что 3-е целое число / указатель его вызывающего аргумента.
sec
0.0 в вызываемом абоненте, по-видимому, случайно. Он просто использует то, что сидело в XMM0. Или, возможно, неинициализированное пространство стека, так как вызывающая сторона установит AL=0
чтобы указать, что в регистрах не переданы аргументы FP (необходимо только для функций с переменными числами). Заметка al
= количество аргументов регистра fp включает фиксированные невариационные аргументы, когда доступен прототип. Компиляция вашего звонка с доступным прототипом включает в себя mov eax, 1
перед call
, См. Source+asm для компиляции с / без прототипа в проводнике компилятора Godbolt.
В другом соглашении о вызовах (например, -m32
с аргументами стека), все будет по крайней мере плохо, потому что эти аргументы будут переданы в стек, но int
а также double
разные размеры.
Пишу 0.0
для аргументов FP неявное объявление будет соответствовать определению. Но не делайте этого, по-прежнему ужасно вызывать необъявленные функции. использование -Wall
чтобы компилятор сообщал вам, когда ваш код делает плохие вещи.
Ваша функция все еще может потерпеть крах; кто знает, какие еще ошибки есть в коде, который не показан?
Когда ваш код вылетает, вы должны посмотреть на инструкцию asm, на которой он вылетел, чтобы выяснить, какой указатель был плохим - например, запустить disas
в гдб. Даже если вы сами этого не понимаете, вопрос о помощи в отладке (вместе со значениями регистра) может сильно помочь.