OpenBSD und Propolice

Paldium

Well-Known Member
Bei meinen ersten Versuchen, C anhand des Quelltextes von OpenBSD besser verstehen zu können, bin ich auf ein paar Dinge gestoßen, die ich mir nicht erklären kann ... Ich hoffe, dass ihr mir weiterhelfen könnt.

Zum einen ist mir der unterschiedliche Einsatz von "exit" und "return" am Ende der main()-Funktion aufgefallen. Ich hatte mal gelesen, dass beides zum gleichen Ergebnis führen soll, habe aber dennoch mal auf meinem OpenBSD-3.7-System ausprobiert, ob das stimmt. Ich habe folgende einfache Programme genutzt:

Code:
int
main(int argc, char *argv[])
{
    return 0;
}
und
Code:
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    exit(0);
}

So weit, so gut, die Programme machen natürlich genau das, was sie machen sollen. Da ich aber wissen wollte, wo genau der Unterschied im Ablauf ist, habe ich mir mit "gcc -S return.c" und "gcc -S exit.c" den Assemblercode ausgeben lassen. Dabei ist mir dann aufgefallen, dass propolice nur in return.s zum Greifen kommt. Wenn ich das Programm mit exit beende, dann wird __guard zwar initialisiert, aber niemals überprüft.

Ein Programm, bei dem ich jetzt nicht verstehe, warum mit "exit" beendet wird, ist /bin/cat. Selbst wenn es sinnlos erscheint, propolice zu aktivieren... es wird ja gemacht, schließlich wird zu Beginn __guard initialisiert. Wenn ich mir mit "gcc -S cat.c" den Assemblercode ansehe, wird aber kein __stack_smash_handler aufgerufen, wodurch der ganze Schutz hinfällig ist.

Meine Frage daher: Gibt es einen guten Grund dafür, am Ende von bin/cat "exit(retval)" statt "return retval" aufzurufen? "return retval" hätte ja eine Überprüfung von __guard zur Folge ...
 
Beispiel

Um mal ein Beispiel anzubringen, für die, die sich vielleicht nicht ganz vorstellen können, was ich meine:

Zum einen dieser Durchlauf (mit return):
Code:
#include <stdio.h>

int
main(int argc, char *argv[])
{
        char array[5];
        sprintf(array, "sehr viel laenger als 5 Zeichen");
        return 0;
}

Code:
$ gcc -o propolice propolice.c
$ ./propolice
Abort trap (core dumped)
$ _

Jetzt der Durchlauf mit exit:
Code:
#include <stdio.h>

int
main(int argc, char *argv[])
{
        char array[5];
        sprintf(array, "sehr viel laenger als 5 Zeichen");
        exit(0);
}

Code:
$ gcc -o nopropolice nopropolice.c
$ ./nopropolice
$ _
 
Nun, es gibt da einige Unterschiede zwischen return und exit und zwar:

return ist ein Schlüsselwort und exit ist eine Standard-Funktion, deren Definition du in stdlib.h finden kannst. Bei return ist dies, was ja klar sein dürfte, nicht vorhanden/notwendig.

Auch besteht der Unterschied is der Tatsache, dass exit von jeder beliebigen Funktion aus das Programm beenden kann, während return nur in der (Haupt)Funktion main eine Beendigung der Programms verursachen würde.

Und weil Propolice was mit dem Compiler zu tun hat (ist in ihm drin und läuft per default unter OpenBSD) und der Compiler "seine" Befehle auf Anhieb kennt, ist es ja klar, dass er schon "im Voraus" sehen kann, was geschehen kann bzw. wird.

So wie in deinem Beispiel.

Zumindest erkläre ich es mir so. Aber, vielleicht gibt es noch versiertere Programmierer als mich, die uns noch mehr an guten Infos liefern würden.

Würde mich echt mal interessieren, ob es einen anderen Grund gibt.

Na ja, was heißt denn hier "vielleicht gibt es noch versiertere Programmierer" ... natürlich gibt es welche, wir sind doch DAS Board für BSD ;)

Grüße
 
Zuletzt bearbeitet:
Zurück
Oben