Ошибка сегментации в длинной строке
Я пишу функцию, которая выводится в виде стандартного вывода, как, например, обычная функция printf, но вместо того, чтобы принимать такие индикаторы, как%d или%s, для этого требуется {i} или {s}. У меня проблема в том, что когда строка аргумента формата слишком длинная, около 23 символов, я получаю ошибку сегментации в строке, где я вызываю функцию vfprintf.
int mr_asprintf(const char *format, ...)
{
int i;
char *newFormat = calloc(1,sizeof(char));
char integer[3] = "%d";
char str[3] = "%s";
char tmpStr[2];
va_list args;
newFormat[0] ='\0';
tmpStr[1] = '\0';
for(i=0;format[i]!='\0';i++) // convert to printf syntaxe
{
if(format[i]=='{' && format[i+2]=='}') //check if it's {x}
{
switch(format[i+1])
{
case 'i':
strcat(newFormat,integer);
i += 2;
break;
case 's':
strcat(newFormat,str);
i += 2;
break;
}
}
else
{
tmpStr[0] = format[i];
strcat(newFormat,tmpStr);
}
}
va_start(args,format);
int s = vfprintf(stdout,newFormat,args);
va_end(args);
free(newFormat);
return s;
}
Тестовый пример:
int main()
{
char *result = mr_asprintf("bce }edadacba{i}}aa}da{s}fe aeaee d{i}cefaa",55,"XXX",66);
printf("%s\n",result);
return 0;
}
1 ответ
Ваша строка newFormat
выделяется как размер 1, и вы добавляете к нему с помощью strcat - но strcat не изменяет размер массива, поэтому newFormat
скоро начнет топать по незанятой памяти. Длина вашей выходной строки всегда будет <= длина входной строки, поэтому вам, вероятно, следует выделить строку такого размера.
Наконец, хотя это не должно вызывать segfault в vprintf, это может вызвать неожиданное поведение позже -
for(i=0;format[i]!='\0';i++) // convert to printf syntaxe
{
if(format[i]=='{' && format[i+2]=='}') //check if it's {x}
Вы проверяете, является ли текущее местоположение концом строки, а затем проверяете два символа после текущего местоположения на наличие закрывающей скобки, не проверяя, закончилась ли строка в следующем пробеле. Это может привести к чтению за пределами выделенной памяти для вашего массива. Замена оператора if на if(format[i]=='{' && (format[i+1]=='i' || format[i+1]=='s') && format[i+2]=='}')
бы избежать проблемы.