Является ли «argv [0] = имя исполняемого файла» принятым стандартом или просто общепринятым соглашением?
102
При передаче аргумента main()в приложение C или C ++ argv[0]всегда будет имя исполняемого файла? Или это просто обычное соглашение и не гарантируется, что оно будет верным в 100% случаев?
В Unix, рассмотрим: execl("/home/hacker/.hidden/malicious", "/bin/ls", "-s", (char *)0);. Имя исполняемого файла не имеет отношения к значению в argv[0].
Джонатан Леффлер,
Ответы:
119
Предположения (даже обоснованные предположения) - это весело, но вам действительно нужно обратиться к документам стандартов, чтобы быть уверенным. Например, ISO C11 гласит (выделено мной):
Если значение argcбольше нуля, строка, на которую указывает, argv[0]представляет имя программы; argv[0][0]должен быть нулевым символом, если имя программы недоступно в среде хоста.
Так что нет, это только имя программы, если оно доступно. И это «представляет» название программы, не обязательно является названием программы. В разделе перед этим говорится:
Если значение argcбольше нуля, элементы массива argv[0]до argv[argc-1]включительно должны содержать указатели на строки, которым среда хоста присваивает значения, определяемые реализацией, до запуска программы.
Это не отличается от C99, предыдущего стандарта, и означает, что даже значения не продиктованы стандартом - это полностью зависит от реализации.
Это означает, что имя программы может быть пустым, если среда хоста его не предоставляет, и что-либо еще, если среда хоста его предоставляет, при условии, что «что-нибудь еще» каким-то образом представляет имя программы. В мои более садистские моменты я бы подумал о том, чтобы перевести его на суахили, пропустить через шифр подстановки, а затем сохранить в обратном порядке байтов :-).
Однако реализация определенная действительно имеет определенное значение в стандартах ISO - реализация должна документировать , как это работает. Так что даже UNIX, который может помещать все, что угодно, argv[0]с execсемейством вызовов, должен (и делает) это документально.
Это может быть стандартом, но unix просто не обеспечивает его соблюдения, и вы не можете рассчитывать на это.
dmckee --- котенок экс-модератора
4
Вопрос не говоря уже о UNIX вообще . Это был простой и ясный вопрос на языке C, поэтому ISO C является справочным документом. Имя программы - это реализация, определенная в стандарте, поэтому реализация может делать то, что хочет, в том числе разрешать что-то, что не является фактическим именем - я думал, что ясно дал это понять в предпоследнем предложении.
paxdiablo
2
Пакс, я не голосовал против вас и не одобряю тех, кто проголосовал, потому что этот ответ настолько авторитетен, насколько это возможно . Но я думаю, что ненадежность значения argv[0]имеет отношение к программированию в реальном мире.
dmckee --- котенок экс-модератора
4
@caf, это правильно. Я видел, что он содержит такие разные вещи, как полный путь к программе ('/ progpath / prog'), только имя файла ('prog'), слегка измененное имя ('-prog'), описательное имя (' прога - программа для прогонки ') и ничего (' '). Реализация должна определять, что в ней содержится, но это все, что требует стандарт.
paxdiablo
3
Спасибо всем! Отличное обсуждение из (казалось бы) простого вопроса. Хотя ответ Ричарда действителен для операционных систем * nix, я выбрал ответ paxdiablo, потому что меня меньше интересует поведение конкретной ОС и в первую очередь интересует наличие (или отсутствие) принятого стандарта. (Если вам интересно: в контексте исходного вопроса - у меня нет операционной системы. Я пишу код для создания необработанного буфера argc / argv для исполняемого файла, загруженного на встроенное устройство, и мне нужно знать, что мне делать с argv [0]). +1 к StackOverflow за то, что он классный!
Майк Виллекес,
49
В *nixсистемах типов с exec*()вызовами argv[0]это будет то, что вызывающий абонент ставит на argv0место в exec*()вызове.
Оболочка использует соглашение, что это имя программы, и большинство других программ следуют тому же соглашению, поэтому argv[0]обычно это имя программы.
Но мошенническая программа Unix может вызывать exec()и создавать argv[0]все, что ей заблагорассудится, поэтому независимо от того, что говорит стандарт C, вы не можете рассчитывать на это в 100% случаев.
Это лучший ответ, чем приведенный выше paxdiablo. Стандарт просто называет это «именем программы», но, насколько мне известно, это нигде не применяется. Ядра Unix равномерно передают строку, переданную в execve (), дочернему процессу.
Энди Росс,
4
Стандарт C ограничен в том, что он может сказать, потому что он не знает о execve () и т. Д. Стандарт POSIX ( opengroup.org/onlinepubs/9699919799/functions/execve.html ) может сказать больше - проясняет что то, что находится в argv [0], является прихотью процесса, который выполняет системный вызов execve () (или связанный с ним).
Джонатан Леффлер,
1
@ Энди, вы можете высказать свое мнение :-) Но вы ошибаетесь насчет правоприменения. Если реализация не соответствует стандарту, значит, она не соответствует. И на самом деле, поскольку реализация определяется в отношении того, что такое «имя программы», ОС, такая как UNIX , соответствует требованиям, если в ней указано имя. Это включает в себя возможность явно подделать имя программы, загрузив в argv [0] все, что вы хотите, в семействе вызовов exec.
paxdiablo
В этом прелесть слова «представляет» в стандарте, когда оно относится к argv [0] («представляет имя программы») и argv [1..N] («они представляют аргументы программы»). "незагруженная ласточка" - допустимое название программы.
Ричард Пеннингтон,
9
Согласно стандарту C ++, раздел 3.6.1:
argv [0] должен быть указателем на начальный символ NTMBS, который представляет имя, используемое для вызова программы, или ""
Так что нет, это не гарантируется, по крайней мере, стандартом.
Я предполагаю, что многобайтовая строка с завершающим нулем?
paxdiablo
6
ISO-IEC 9899 утверждает:
5.1.2.2.1 Запуск программы
Если значение argcбольше нуля, строка, на которую указывает, argv[0]представляет имя программы; argv[0][0]должен быть нулевым символом, если имя программы недоступно в среде хоста. Если значение argcбольше единицы, строки, на которые указывает argv[1]through, argv[argc-1]представляют параметры программы .
/proc/self/path/a.outСимволическая может использоваться на Solaris 10 и выше.
ephemient
Проголосовали за код (не говоря, что он идеальный или правильный, например, в Windows GetModuleFileNameWследует использовать для получения любого пути, но только наличие кода является хорошим руководством).
Приветствия и hth. - Alf
4
Приложения с argv[0] !=исполняемым именем
многие оболочки определяют, являются ли они оболочкой входа, путем проверки argv[0][0] == '-'. Оболочки входа в систему имеют разные свойства, в частности то, что они являются источником некоторых файлов по умолчанию, таких как /etc/profile.
бинарные файлы с несколькими вызовами, возможно, в первую очередь Busybox . Эти символические ссылки на несколько имен, например, /bin/shи /bin/lsна один исполняемый файл /bin/busybox, который распознает, какой инструмент использовать argv[0].
Это позволяет иметь один небольшой статически связанный исполняемый файл, который представляет несколько инструментов и будет работать практически в любой среде Linux.
Элемент argv [0] обычно содержит имя программы, но на него не следует полагаться - в любом случае программа не знает своего имени!
Однако другие страницы, похоже, подтверждают тот факт, что это всегда имя исполняемого файла. В нем говорится:
Вы заметите, что argv [0] - это путь и имя самой программы. Это позволяет программе обнаруживать информацию о себе. Он также добавляет еще один к массиву аргументов программы, поэтому распространенной ошибкой при получении аргументов командной строки является захват argv [0], когда вы хотите argv [1].
Некоторые программы используют тот факт, что они не знают имени, которое использовалось для их вызова. Я считаю, что BusyBox ( busybox.net/about.html ) работает именно так. Есть только один исполняемый файл, который реализует множество различных утилит командной строки. Он использует набор символических ссылок и argv [0], чтобы определить, какой инструмент командной строки следует запустить
Трент
Да, я помню, как заметил, что «gunzip» был символической ссылкой на «gzip», и на мгновение задумался, как это работает.
Дэвид Торнли,
2
Многие программы ищут информацию в argv [0]; например, если последний компонент имени начинается с тире (например, '/ bin / -sh'), тогда оболочка запустит профиль и другие вещи, как для оболочки входа.
Джонатан Леффлер,
2
@Jon: Я думал, что оболочки входа в систему были запущены argv[0]="-/bin/sh"? Во всяком случае, так обстоит дело на всех машинах, которые я использовал.
ephemient
3
Я не уверен, является ли это почти универсальным соглашением или стандартом, но в любом случае вы должны его соблюдать. Однако я никогда не видел, чтобы он использовался за пределами Unix и Unix-подобных систем. В средах Unix - и, возможно, особенно в былые времена - программы могли иметь существенно разное поведение в зависимости от имени, под которым они вызывались.
EDITED: из других сообщений одновременно с моими я вижу, что кто-то определил, что это происходит из определенного стандарта, но я уверен, что соглашение задолго до этого стандарта.
execl("/home/hacker/.hidden/malicious", "/bin/ls", "-s", (char *)0);
. Имя исполняемого файла не имеет отношения к значению вargv[0]
.Ответы:
Предположения (даже обоснованные предположения) - это весело, но вам действительно нужно обратиться к документам стандартов, чтобы быть уверенным. Например, ISO C11 гласит (выделено мной):
Так что нет, это только имя программы, если оно доступно. И это «представляет» название программы, не обязательно является названием программы. В разделе перед этим говорится:
Это не отличается от C99, предыдущего стандарта, и означает, что даже значения не продиктованы стандартом - это полностью зависит от реализации.
Это означает, что имя программы может быть пустым, если среда хоста его не предоставляет, и что-либо еще, если среда хоста его предоставляет, при условии, что «что-нибудь еще» каким-то образом представляет имя программы. В мои более садистские моменты я бы подумал о том, чтобы перевести его на суахили, пропустить через шифр подстановки, а затем сохранить в обратном порядке байтов :-).
Однако реализация определенная действительно имеет определенное значение в стандартах ISO - реализация должна документировать , как это работает. Так что даже UNIX, который может помещать все, что угодно,
argv[0]
сexec
семейством вызовов, должен (и делает) это документально.источник
argv[0]
имеет отношение к программированию в реальном мире.В
*nix
системах типов сexec*()
вызовамиargv[0]
это будет то, что вызывающий абонент ставит наargv0
место вexec*()
вызове.Оболочка использует соглашение, что это имя программы, и большинство других программ следуют тому же соглашению, поэтому
argv[0]
обычно это имя программы.Но мошенническая программа Unix может вызывать
exec()
и создаватьargv[0]
все, что ей заблагорассудится, поэтому независимо от того, что говорит стандарт C, вы не можете рассчитывать на это в 100% случаев.источник
Согласно стандарту C ++, раздел 3.6.1:
Так что нет, это не гарантируется, по крайней мере, стандартом.
источник
ISO-IEC 9899 утверждает:
Я также использовал:
А затем вам просто нужно проанализировать строку, чтобы извлечь имя исполняемого файла из пути.
источник
/proc/self/path/a.out
Символическая может использоваться на Solaris 10 и выше.GetModuleFileNameW
следует использовать для получения любого пути, но только наличие кода является хорошим руководством).Приложения с
argv[0] !=
исполняемым именеммногие оболочки определяют, являются ли они оболочкой входа, путем проверки
argv[0][0] == '-'
. Оболочки входа в систему имеют разные свойства, в частности то, что они являются источником некоторых файлов по умолчанию, таких как/etc/profile
.Обычно это сам init или
getty
добавляющий ведущий-
, см. Также: /unix/299408/how-to-login-automatically-without-typing-the-root-username-or-password -in-build / 300152 # 300152бинарные файлы с несколькими вызовами, возможно, в первую очередь Busybox . Эти символические ссылки на несколько имен, например,
/bin/sh
и/bin/ls
на один исполняемый файл/bin/busybox
, который распознает, какой инструмент использоватьargv[0]
.Это позволяет иметь один небольшой статически связанный исполняемый файл, который представляет несколько инструментов и будет работать практически в любой среде Linux.
См. Также: /unix/315812/why-does-argv-include-the-program-name/315817
execve
Примерargv[0] !=
исполняемого POSIX, где имя исполняемого файлаДругие упоминались
exec
, но вот работоспособный пример.ac
До нашей эры
Затем:
Дает:
Да,
argv[0]
также может быть:Проверено на Ubuntu 16.10.
источник
На этой странице говорится:
Однако другие страницы, похоже, подтверждают тот факт, что это всегда имя исполняемого файла. В нем говорится:
источник
argv[0]="-/bin/sh"
? Во всяком случае, так обстоит дело на всех машинах, которые я использовал.Я не уверен, является ли это почти универсальным соглашением или стандартом, но в любом случае вы должны его соблюдать. Однако я никогда не видел, чтобы он использовался за пределами Unix и Unix-подобных систем. В средах Unix - и, возможно, особенно в былые времена - программы могли иметь существенно разное поведение в зависимости от имени, под которым они вызывались.
EDITED: из других сообщений одновременно с моими я вижу, что кто-то определил, что это происходит из определенного стандарта, но я уверен, что соглашение задолго до этого стандарта.
источник
Если вы запустите программу Amiga с помощью Workbench, argv [0] не будет установлен, только с помощью интерфейса командной строки.
источник