В качестве точки данных я скомпилировал и запустил следующие программы на нескольких системах.(Отказ от ответственности: эти программы предназначены для предоставления точки данных, но, как мы увидим, они не в конечном итоге отвечают на вопрос, как указано.)
p1.c
:
#include <stdio.h>
#include <unistd.h>
int main()
{
char test[] = "test";
execl("./p2", "p2", test, test, NULL);
}
p2.c
:
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for(i = 1; i < argc; i++) printf("%s ", argv[i]); printf("\n");
argv[1][0] = 'b';
for(i = 1; i < argc; i++) printf("%s ", argv[i]); printf("\n");
}
В каждом месте, где я пробовал (под MacOS и несколькими версиями Unix и Linux), напечатано
test test
best test
Поскольку вторая строка никогда не была "best best
", это доказывает, что в тестируемых системах к моменту запуска второй программы строки больше не псевдонимы.
Конечно, этот тест делает not доказывает, что строки в argv
никогда не могут быть псевдонимами ни при каких обстоятельствах ни при каких системах.Я думаю, что все это доказывает, что неудивительно, что каждая из протестированных операционных систем переписывает список аргументов, по крайней мере, один раз между временем p1
вызовов execl
и временем фактического вызова p2
.Другими словами, вектор аргумента, созданный вызывающей программой, не используется непосредственно в вызываемой программе, и в процессе его копирования он (опять-таки не удивительно) «нормализуется», что означает, что эффектылюбого псевдонима теряется.
(я говорю, что это не удивительно, потому что если вы подумаете о том, как на самом деле работает семейство системных вызовов exec
, и как распределяется память процесса в Unix-подобных системахнет никакого способа, которым список аргументов вызывающей программы можно было бы использовать напрямую: он имеет , который должен быть скопирован, по крайней мере, один раз, в адресное пространство нового, исполняемого процесса процесса. Кроме того, любой очевидный и прямойметод копирования списка аргументов всегда и автоматически собирается «нормализовать» его таким образом, ядру придется проделать значительную, дополнительную, совершенно ненужную работу, чтобы обнаружить и сохранить любой псевдоним.)
Простоесли это имеет значение, я изменил первую программу следующим образом:
#include <stdio.h>
#include <unistd.h>
int main()
{
char test[] = "test";
char *argv[] = {"p2", test, test, NULL};
execv("./p2", argv);
}
Results не изменились.
С учетом всего вышесказанного я согласен с тем, что эта проблема в стандартах кажется упущением или ошибкой.Я не знаю ни одного предложения, гарантирующего, что строки, на которые указывает argv
, различны, а это означает, что параноидально написанная программа, вероятно, не может зависеть от такой гарантии, независимо от того, насколько это вероятно (как показывает этот ответ) любая разумная реализация, вероятно, сделает это таким образом.