ограничение длины строки функции system () - PullRequest
10 голосов
/ 13 апреля 2019

Как долго может быть передана строка system()?

Я знаю, что POSIX минимум составляет 4096, но я хотел бы знать фактический размер, который я могу использовать.Для этого есть какой-либо макрос, подобный FILENAME_MAX?

char cmd[SOME_MACRO];

...
system(cmd);

Ответы [ 3 ]

9 голосов
/ 13 апреля 2019

system exec - оболочка с аргументами "sh","-c", YourAgumentToSystem, (char*)0 ( гарантируется POSIX ), поэтому максимальная длина (не считая терминатора '\0') составляет ARG_MAX -1 -3 -3 - size_of_your_environment.

ARG_MAX определяется в limit.h как

"Максимальная длина аргумента для функций exec, включая данные среды."

Если limits.h, не определяет ARG_MAX, вы должны иметь возможность вызывать sysconf(_SC_ARG_MAX) для получения лимита времени выполнения.

Страница Linux для execve (вызывается системой) предоставляет дополнительную информацию:

В Linux до ядра 2.6.23 объем памяти, используемой для хранения среды и строк аргументов, был ограничен 32 страницами (определяемыми константой ядра MAX_ARG_PAGES).На архитектурах с размером страницы 4 КБ это дает максимальный размер 128 КБ.

В ядре 2.6.23 и более поздних версиях большинство архитектур поддерживают ограничение размера, полученное из мягкого ограничения ресурса RLIMIT_STACK (см. Getrlimit (2)), который действует во время вызова execve ().(Архитектуры без модуля управления памятью исключаются: они поддерживают предел, который действовал до ядра 2.6.23.) Это изменение позволяет программам иметь гораздо больший аргумент и / или список окружения.Для этих архитектур общий размер ограничен 1/4 разрешенного размера стека.(Введение предела 1/4 гарантирует, что новая программа всегда имеет некоторое пространство в стеке.) Начиная с Linux 2.6.25, ядро ​​помещает пол в 32 страницы на этот предел размера, так что даже когда RLIMIT_STACK установлен на очень низкое значение,приложения гарантированно имеют как минимум столько же аргументов и пространства среды, сколько было предоставлено в Linux 2.6.23 и более ранних версиях.(Эта гарантия не была предоставлена ​​в Linux 2.6.23 и 2.6.24.) Кроме того, ограничение на строку составляет 32 страницы (константа ядра MAX_ARG_STRLEN), а максимальное количество строк - 0x7FFFFFFF.

Чтобы измерить размер вашей среды, вы можете запустить:

extern char **environ;
size_t envsz = 0; for(char **e=environ; *e; e++) envsz += strlen(*e)+1;

(Как отмечал Zan Lynx в комментариях, это можно ускорить (около 20в соответствии с моими измерениями - от 1600 нс до 80 нс для 100-струнной среды 6 КБ, которую я имел при измерении), если предположить, что указатели char* в environ указывают на непрерывный буфер, который они делают после запуска программы, но вызываютдо setenv, putenv или unsetenv, как правило, ломайте это:

extern char **environ;
char **e; for(e=environ; *e; e++) {}
size_t envsz =  ($_sz)(e[-1]+strlen(e[-1])+1 - *environ);

В любом случае, ускорение за счет надежности не должно иметь большого значения, если вы ожидаете раскошелиться+ exec (/ system) в ближайшее время, учитывая, что fork + exec обычно стоит минимум 1-2 мс в Linux на современной машине.)

4 голосов
/ 13 апреля 2019

Предел сильно зависит от системы.Это может даже зависеть от командной оболочки, которая будет использоваться.Вы должны проверить возвращаемое значение system(), чтобы увидеть, был ли системный вызов успешным: -1 означает сбой, а errno должен дать вам больше информации.Поведение должно быть определено для любой правильной строки C.

POSIX документы, которые system(command) эквивалентны:

execl(<shell path>, "sh", "-c", command, (char *)0);

А также документы ARG_MAX, определенные в<limits.h> в качестве предела для объединенной длины аргументов exec и переменных среды.

Обратите внимание, однако, что command может содержать символы подстановки и / или другие слова оболочки, расширение которых может превышать какой-либо другой предел,Всегда проверяйте возвращаемое значение на предмет ошибки.

3 голосов
/ 13 апреля 2019

человек 3 система

дает нам

ОПИСАНИЕ

Функция библиотеки system () использует fork (2) для создания дочернего процесса, который выполняет команду оболочки, указанную в команде используя execl (3) следующим образом:

       execl("/bin/sh", "sh", "-c", command, (char *) 0);

   system() returns after the command has been completed.

поэтому system () является оберткой для execl()

С той же страницы мы также видим, что этот вызов соответствует некоторым стандартам.

СООТВЕТСТВУЮЩИМ

POSIX.1-2001, POSIX.1-2008, C89, C99.

Глядя вверх POSIX.1-2008 выдает следующую онлайн справку

https://pubs.opengroup.org/onlinepubs/9699919799/

Где мы можем найти информацию о функции execl, которая выводит нас на

https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html

Который предлагает следующее

Число байтов, доступных для комбинированных списков аргументов и среды нового процесса, равно {ARG_MAX}. Это зависит от реализации, включены ли в эту сумму нулевые терминаторы, указатели и / или байты выравнивания.

И наконец ...

ОШИБКИ

Функции exec не будут работать, если:

[E2BIG] Число байтов, используемых аргументом нового образа процесса список и список среды больше, чем установленный системой предел {ARG_MAX} байт.

Таким образом, последняя проверка, которую следует выполнить, - это фактическая реализация exec, а не использование стандарта на случай, если реализация отклонится от стандарта.

Итак, man 3 execl сообщает, что возвращенные ошибки совпадают с документально подтвержденными для execve(2), а man 2 execvw сообщает следующее:

ОШИБКА

E2BIG Общее количество байтов в среде (envp) и списке аргументов (argv) слишком велико.

Не так точно, как стандарт POSIX? Лучше всего проверить код или увидеть (сейчас) принятый ответ:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...