Можно ли передавать строковые литералы в argv posix_spawn? - PullRequest
0 голосов
/ 30 мая 2018

Для функция posix_spawn имеет прототип:

int posix_spawn(pid_t *restrict pid, const char *restrict path,
   const posix_spawn_file_actions_t *file_actions,
   const posix_spawnattr_t *restrict attrp,
   char *const argv[restrict], char *const envp[restrict]);

Примечательно, что параметр argv указывает на массив из char * указателей (то есть указателей на изменяемые символы).Кроме того, документация не дает никаких гарантий того, что данные не будут записаны.

Мой вопрос: есть ли где-нибудь гарантия, что можно передавать строковый литерал?Или мы рискуем segfault?

Пример кода:

char *v[] = { "foo.exe", "bar", NULL };
posix_spawn( NULL, "foo.exe", NULL, NULL, v, NULL );

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

есть ли где-нибудь гарантия, что можно передавать строковый литерал?Или мы рискуем segfault?

Учитывая, что существует технический риск segfault, так как argv ожидает не const массив char* и предоставление строкового литерала может привести к UB.С помощью функции, возможно моделирующей main(int argc, char *argv[]), код может записывать в argv[0].

int main(int argc, char *argv[])
...
Параметры argc и argv и строкиуказанный в массиве argv должен быть изменяемым программой и сохранять их последние сохраненные значения между запуском программы и завершением программы.C11 §5.1.2.2.1 2

int foo(......., char *const argv[restrict], char *const envp[restrict]);

char *v[] = { "foo.exe", "bar", NULL };
foo( NULL, "foo.exe", NULL, NULL, v, NULL );

Альтернатива

Хотя с posix_spawn(), я сомневаюсь, что произойдет запись,Решение с C99 использует составной литерал вместо строкового литерала и, таким образом, исключает потенциал UB.

// char *v[] = { "foo.exe", "bar", NULL };
char *v2[] = { (char [8]){"foo.exe"}, (char [4]){"bar"}, NULL };
posix_spawn( NULL, "foo.exe", NULL, NULL, v2, NULL );

Теперь posix_spawn() может записывать в v2[0]

0 голосов
/ 30 мая 2018

Использование строковых литералов здесь совершенно нормально.

Независимо от того, указывает ли аргумент указателя (или данные указателя, на который указывает аргумент) на константный тип, не имеет ничего общего с тем, может ли функция изменять указательдля объекта.Это чисто вопрос контракта рассматриваемой функции.Как правило, обычно предпочтительнее использовать указатели с константным указателем в аргументах, когда объект не будет изменен:

  1. , чтобы разрешить передачу указателей на объекты с константным уточнением без приведения, и
  2. как указание на то, что объект не будет изменен.

, но это не требуется для языка Си.А для функций, которые используют типы двойных указателей в своих интерфейсах, здесь часто есть компромисс.Поскольку T * и const T * не могут использовать псевдонимы друг друга, интерфейс должен выбирать форму, более подходящую для вызывающей стороны;если вызывающая сторона хочет другую форму, она должна сделать временную копию для передачи в функцию.Это относится к posix_spawn.

. В общем, когда речь идет о стандартных функциях (C или POSIX), они не могут иметь каких-либо наблюдаемых побочных эффектов, кроме указанных .Если ОПИСАНИЕ для функции не документирует, что она изменит объект, «принадлежащий» приложению, или к которому приложение имеет доступ, оно не сможет изменить его;это не соответствует.Вот почему функции, которые возвращают указатели на статическое хранилище, явно документируют это.Например, документы POSIX для strerror:

Возвращенный указатель строки может быть недействительным или содержимое строки может быть перезаписано последующим вызовом strerror (),

За исключением такой документации, приложение может предположить, что строка, возвращаемая strerror, никогда не изменяется реализацией.

Поскольку posix_spawn не задокументировано для изменения строк, на которые указывает массив argv, он не изменяет их.

Кроме того, обратите внимание, что posix_spawn должен быть поточно-ориентированным и не накладывает никаких явных ограничений на приложения для одновременного доступа к строкам argv.Таким образом, любая модификация привела бы к гонкам данных, что сделало бы posix_spawn не поточно-безопасным, вопреки спецификации.

0 голосов
/ 30 мая 2018

Я почти уверен, что тип был выбран для совместимости с аргументом char **argv для mainexecve).(Хотя в традиционной реализации с надлежащим разделением процессов ядро ​​в конечном итоге должно сделать копию.)

POSIX, похоже, не говорит о том, что эти массивы изменены, но я вполне уверен, что ни одна из существующих реализаций не будетизменить их.Могут быть некоторые причины для использования разных аргументов (и имен исполняемых файлов), но они будут длиннее , поэтому posix_spawn все равно должен выделить память для копии и не сможет выполнить модификацию на месте.

...