Ошибка сегментации в длинной строке

Я пишу функцию, которая выводится в виде стандартного вывода, как, например, обычная функция 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]=='}') бы избежать проблемы.

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