Wann kann argv[0] null haben?

Lesezeit: 6 Minuten

Benutzer-Avatar
Andrew-Dufresne

Was ich über die Übergabe von Argumenten an main() von der Befehlszeile aus verstanden habe, ist, dass argc einen Mindestwert von 1 und argv hat[0] wird immer den Programmnamen mit seinem Pfad enthalten.

Wenn Argumente in der Befehlszeile bereitgestellt werden, hat argc einen Wert größer als eins und argv1 zu argv[argc-1] wird diese Argumente haben.

Jetzt ein Absatz bei dieser Link sagt, dass

argv[0] wird eine Zeichenfolge sein, die den Namen des Programms enthält oder eine Nullzeichenfolge wenn das nicht vorhanden ist.

Nun, wie und wann kann argv[0] Nullstring haben? Ich meine, der Programmname mit seinem Pfad wird immer verfügbar sein, also wann kann er null sein?

Writer sagt, dass “wenn das nicht verfügbar ist”, aber wann und wie ist es möglich, dass der Programmname nicht verfügbar ist?

  • @Ciro Santilli 烏坎事件2016六四事件 法轮功 – Wenn Sie sich die gestellten und beantworteten Daten ansehen, werden Sie sehen, dass diese Frage ein Duplikat von stackoverflow.com/questions/2336027/why-check-if-argv-null ist, nicht umgekehrt.

    – Shaun Hammann

    17. Februar 2017 um 19:38 Uhr

  • @ShaunHamman Der derzeitige Konsens besteht darin, mit “Qualität” zu schließen: meta.stackexchange.com/questions/147643/… Da “Qualität” nicht messbar ist, gehe ich einfach nach Upvotes. 😉 Wahrscheinlich kommt es darauf an, welche Frage die besten Newb-Google-Keywords auf den Titel trifft.

    – Ciro Santilli OurBigBook.com

    17. Februar 2017 um 20:20 Uhr

Benutzer-Avatar
paxdiablo

Mit dem exec Klasse von Aufrufen geben Sie das Programm vor Name und Programm ausführbar separat, damit Sie es dann auf NULL setzen können.

Aber dieses Zitat stammt eigentlich aus dem ISO-Standard (möglicherweise paraphrasiert), und dieser Standard deckt eine schrecklich große Bandbreite von Ausführungsumgebungen ab, vom kleinsten Mikrocontroller bis zum neuesten Mainframe der z10-Enterprise-Klasse.

Viele dieser eingebetteten Systeme wären in der Situation, in der ein ausführbarer Name wenig Sinn macht.

Aus dem neuesten c1x-Entwurf:

Der Wert von argc soll nichtnegativ sein.

Der Wert argv[argc] soll ein Nullzeiger sein.

Wenn der Wert von argc größer als Null ist, die Array-Mitglieder argv[0] durch argv[argc-1] inclusive soll Zeiger auf Strings enthalten, denen vor dem Programmstart implementierungsdefinierte Werte von der Host-Umgebung gegeben werden.

Das bedeutet, wenn argc Null ist (und es sein kann), argv[0] ist Null.

Aber selbst wenn argc ist nicht 0 erhalten Sie möglicherweise nicht den Programmnamen, da der Standard auch besagt:

Wenn der Wert von argc größer als Null ist, die Zeichenfolge, auf die von gezeigt wird argv[0] stellt den Programmnamen dar; argv[0][0] soll das Nullzeichen sein, wenn der Programmname nicht aus der Hostumgebung verfügbar ist. Wenn der Wert von argc größer als eins ist, wird auf die Zeichenfolgen verwiesen argv[1] durch argv[argc-1] stellen die Programmparameter dar.

Daher gibt es im Standard keine Anforderung, einen Programmnamen anzugeben. Ich habe gesehen, dass Programme eine große Auswahl an Optionen für diesen Wert verwenden:

  • überhaupt keinen Wert (für vermeintliche Sicherheit).
  • eine dreiste Lüge (z sleep für einen bösartigen Code).
  • der eigentliche Programmname (z sleep).
  • ein leicht modifiziertes (z -ksh für die Login-Shell).
  • ein aussagekräftiger Name (z. progname - a program for something).

  • Ich würde schwören, dass ich gerade jemanden sagen hörte: “Warp-Faktor eins, Mr. Sulu”, als ich “Mainframe der Enterprise-Klasse” las …

    – Bob Jarvis – Слава Україні

    13. April 2018 um 2:52 Uhr


Benutzer-Avatar
Mark Ruschakoff

Entsprechend diese Mailingliste, argv[0] kann null sein, wenn argc == 0. Aber sie erklären es nicht Wenn argc könnte jemals null sein. Ich würde vermuten argc wäre Null in Situationen, in denen eine ausführbare Datei nicht “normal” gestartet wurde (dh über eine Befehlszeile, popenetc.) — und tatsächlich, wie @paxdiablo erwähnt, können Sie manuell festlegen argv mit dem exec Familie von FunktionenAlso argc könnte abhängig von diesen Argumenten Null sein.

Aber in ihrer Begründung Sektion:

Frühe Vorschläge erforderten, dass der Wert von argc weitergereicht an main() „eins oder größer“ sein. Dies wurde durch die gleiche Anforderung in Entwürfen der ISO-C-Norm vorangetrieben. Tatsächlich haben historische Implementierungen einen Wert von Null übergeben, wenn keine Argumente an den Aufrufer der exec-Funktionen geliefert wurden. Diese Anforderung wurde aus dem ISO-C-Standard und anschließend auch aus diesem Band von IEEE Std 1003.1-2001 entfernt. Die Formulierung, insbesondere die Verwendung des Wortes should, verlangt von einer streng konformen POSIX-Anwendung, mindestens ein Argument an die exec-Funktion zu übergeben und dies somit zu gewährleisten argc eins oder größer sein, wenn sie von einer solchen Anwendung aufgerufen werden. Tatsächlich ist dies eine bewährte Vorgehensweise, da viele vorhandene Anwendungen darauf verweisen argv[0] ohne vorher den Wert von zu prüfen argc.

Da haben Sie es also: Streng konforme POSIX-Anwendungen müssen vorhanden sein argc größer als Null sein, was aber ansonsten keineswegs gewährleistet ist.

Es gibt ein wenig mehr Informationen über den Standard bzgl argc und argv in dem Programmstart Sektion.

  • Sie fassen die Anforderung rückwärts zusammen. Streng konforme POSIX-Anwendungen von anderen streng konformen POSIX-Anwendungen aufgerufen abhängen kann argc>0 und argv[0] != NULL. Sie müssen auch anrufen execve und verwandte Funktionen so, dass diese Garantie für den untergeordneten Prozess erhalten bleibt. Aber nichts hindert einen böswilligen Benutzer daran, Ihr streng konformes Programm mit auszuführen argc == 0 auf typischen bestehenden POSIX-Systemen. Wenn es setuid ist oder andere besondere Privilegien hat, überprüfen Sie entweder argc oder den Zeiger, oder stellen Sie sicher, dass ein Segfault beim Zugriff auf argv[0] wird nichts kaputt gehen.

    – Peter Cordes

    13. April 2018 um 2:07 Uhr


Benutzer-Avatar
Ciro Santilli OurBigBook.com

Lauffähiges POSIX-Beispiel für argv[0] == NULL

Anrufer.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *argv[] = {NULL};
    char *envp[] = {NULL};
    execve("callee.out", argv, envp);
}

Angerufener.c

#include <stdio.h>

int main(int argc, char **argv) {
    if (argc == 0 && argv[0] == NULL)
        puts("yup");
}

Dann:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o caller.out caller.c
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o callee.out callee.c
./caller.out

Ausgabe:

yup

Bestehendes Programm mit leerer Argumentliste testen

Hier ist ein Wrapper, der einen Pfad als Argument verwendet und diesen als Befehl ohne Argumente ausführt:

Anrufer-beliebig.c

#include <unistd.h>
#include <stdio.h>

int main(int argc, char**argv) {
    char *empty[] = {NULL};
    execve(argv[1], empty, empty);

}

Beispielverwendung:

./caller-any.out /bin/ls

GNU Coreutils-Tools wie ls haben Sie jedoch einen Scheck für argv[0] NULL wie erwähnt unter: Warum kann der Systemaufruf execve “/bin/sh” ohne argv-Argumente ausführen, aber nicht “/bin/ls”? und ls Ausgänge:

A NULL argv[0] was passed through an exec system call.
Aborted (core dumped)

Getestet unter Ubuntu 19.04.

Man kann sich Plattformen vorstellen, auf denen Programme keine Namen haben – vielleicht wird der Code einfach beim Start geladen. Auf diesen, argv[0] könnte ich erraten, NULL sein. Der C-Standard erlaubt sicherlich einen argc-Wert von Null und sagt, dass argv[argc] soll NULL sein.

1382720cookie-checkWann kann argv[0] null haben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy