LINUX.ORG.RU

Функция с двойным количеством неизвестных

 


0

1

Есть некий скрипт, который нужно дернуть из Си-кода. Проблема в том, что скрипт принимает 4 параметра:

script.pl 5 "text 1" 20 "text 2"

В си коде выглядит как-то так (выхлоп скрипта не нужен в принципе):

void ticket_create(u32 code, const char * text, i32 len, const char * file)
{
    char buffer[32768];

    sprintf(buffer,
            "script.pl %d \"%s\" %d \"%s\"",
            code, text, len, file);

    PrintInfo(0, "Going to create ticket: \"%s\"", buffer);

    system(buffer);
}
При этом вызывать `ticket_create` приходится так:
/// 1
    char buffer1[1000];
    char buffer2[1000];
    sprintf(buffer1, "Spl rewind failed in hall %d as SPL \"%s\" in CPL \"%s\".<br>",
            Hall(devindex), target_splid, target_cplid);
    sprintf(buffer2, "/tk/dd24/log/ctms/hall_%d.log", Hall(devindex));
    ticket_create(TICKET_REWIND_FAILED, buffer1, 10, buffer2);

/// 2
        char buffer1[1000];
        char buffer2[1000];
        sprintf(buffer1, "Can't find 'ShowPlaylist.Id' in SPL. SPL's splid is %s in hall %d.",
                splid, Hall(devindex));
        sprintf(buffer2, "/tk/dd24/log/ctms/spls/%d/%s/%s.xml", Hall(devindex), hr_time(10), splid);
        ticket_create(TICKET_SPL_NOID, buffer1, -1, buffer2);

/// 3
            char buffer1[1000];
            char buffer2[1000];
            sprintf(buffer1, "Serials mismatch in hall %d: \'%s\' (db) and \'%s\' (device).",
                    devicesdb.devices[devindex].hallid,
                    devicesdb.devices[devindex].serial, serial);
            sprintf(buffer2, "/tk/dd24/log/ctms/protocol-%d.log",
                    devicesdb.devices[devindex].hallid);
            ticket_create(TICKET_SERIAL_WRONG, buffer1, 50, buffer2);
Бесит, что надо создавать два буфера, сделал бы через эллипсис, но там два неизвестных. Разве что формировать всю строку для подачи скрипту, но это негибко - поменяют синтаксис местами и мне придется не одну функцию менять, а десятки вызовов.

Есть идеи?

★★★★★

Последнее исправление: PPP328 (всего исправлений: 1)

char * sprintf2(const char * format, args...); Строки пусть выделяет в статическом буфере.

anonymous
()

Есть идеи?

Если вы создаёте утилиту, которая работает с параметрами пусть и с примитивной, но некоторой логикой «языка», то надо создавать парсер, который и будет распознавать ввод, и от предыдущего распознаного значения готовится принимать следующее в том или ином статусе.

vodz ★★★★★
()

Собери оба шаблона в одну строку с разделителем (например '\n'), и передавай в ticket_create этот шаблон и параметры для заполнения. После заполнения шаблона через vsprintf(), разбей текст по разделителю на две строки и передавай их скрипту.

cdslow ★★
()
Ответ на: комментарий от anonymous

Многопоточное приложение, статический буфер разве что для каждого потока свой, но потоков штук 30-40, разрастется все.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от vodz

Нет, главная программа- массивный контрольный демон, в котором очень много логики. Дернуть скрипт - это вторичная функция, ради которой большой логики никто крутить не будет.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Есть GNU-тый asprintf. Можно переписать с кривого system() на execlp(), там по аргументам отдельно без буферов. И вообще, вы стек знатно юзаете, и обрежете если таки имена файлов будут большие. Вычисляйте объёмы буферов и алоцируйте для мелких alloca(), для больших - malloc()

vodz ★★★★★
()

Вместо system используй fork + подходящий вариант exec.

system форкает процесс, запускает в нем /bin/sh, который парсит твою тщательно сконкатенированную строку и разбирает ее обратно на массив аргументов, а родительский процесс делает wait и спит пока шелл не завершит работу [напр., 1]

exec же позволяет запустить процесс с массивом аргументов, никакой конкатенации, никакого шелла, никакого парсинга.

[1] https://github.com/kraj/uclibc-ng/blob/master/libc/stdlib/system.c#L26

annulen ★★★★★
()
Ответ на: комментарий от annulen

Кстати, наличие шелла внутри system способствеут появлению уязвимостей в виде выполнения прозиольного кода, если в вызываемую строку могут попасть внешние данные. exec пресекает такие поползновения на корню

annulen ★★★★★
()
Ответ на: комментарий от vodz

malloc()

Стек есть всегда кроме случаев когда мы сами напортачили и выжрали его статическими массивами. Маллок на линуксе может повлечь SIGSEGV если опять сработает эта сраная оптимистичная выделялка. Больше маллоков - также больше вероятность утечки.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Вы же сами написали, что у вас «Многопоточное приложение». Следовательно выжрать кучу это ещё надо очень умудриться, а вот стек в многопоточке как нефиг делать.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Потоки создаются только на старте, после чего они не убывают и не добавляются.

PPP328 ★★★★★
() автор топика
  1. берешь apr
  2. в своем быдлокоде, утыканном дырами в виде переполнения буфера делаешь
    int main()
    {
      apr_initialize();
      ....
    }
    
    // читаешь man execvp, не дожидаясь, пока тебя *** в *** через $() или ``, либо
    const char* shell_arg(apr_pool_t *pool, const char *fmt, ...)
    {
      return 
    }
    
    //
    apr_pool_t *pool;
    apr_pool_create_unmanaged(&pool);
    ticket_create(TICKET_SERIAL_WRONG,
      apr_psprintf(pool, "Serials mismatch in hall %d: \'%s\' (db) and \'%s\' (device).",
                         devicesdb.devices[devindex].hallid,
                         devicesdb.devices[devindex].serial, serial),
      50,
      apr_psprintf(pool, "/tk/dd24/log/ctms/protocol-%d.log", devicesdb.devices[devindex].hallid));
    apr_pool_destroy(&pool);
    
    // затем стимулируешь свой мозг и либо отказываешься от system,
    // либо осваиваешь apr_shell_escape прежде, чем тебя *** в ***
    // через $(rm -fr /*) или `rm -fr /*` и вносишь дальнейшие
    // улучшения в код
    
kawaii_neko ★★★★
()
Ответ на: комментарий от kawaii_neko

А, ну а если ты рулетчик, который только и ждет, когда же его накажут в недостаточно объемный буфер, то просто

#define argsprintf(buf, fmt, ...) ({ \
  snprintf(buf, sizeof(buf), fmt, ##_VA_ARGS__); \
  buf; )}
Надеюсь, самостоятельно сообразишь, как два agrsprintf-а засунуть в свой вызов с разными буферами.

kawaii_neko ★★★★
()
Ответ на: комментарий от kawaii_neko

Строки я формирую сам, те данные, которые формируются в этих строках тоже я положил сам. Если кто-то может залезть в память демону, то ему проще было выполнить rm -rf напрямую. Переполнения буфера не будет с 10тикратным запасом.

Можете и дальше играть в паранойю.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

нет сборки му поэтому приходится ручками (али измышлять как в чикине поколения в стеке и через континуации чёбы прибиралось стеком) а коротышы в Ся е: (в частности частный пример) https://gist.github.com/vidarh/259462

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.