Forum: Compiler & IDEs printf ohne Argumente


von Dennis S. (eltio)


Lesenswert?

Hallo zusammen,
in dem Buch "Writing Secure Code" habe ich einen Quellcode in der 
folgenden Art gefunden:
1
#include <stdio.h>
2
3
void foo(void) {
4
  int x, y;
5
        /* View the stack */
6
  printf("My Stack: \n%p\n%p\n%p\n%p\n%p\n%p\n\n");
7
}
8
9
int main(void) {
10
  printf("Address of foo %p\n", foo);
11
  foo();
12
  return 0;
13
}

Frage: warum funktioniert das?

Gruß
Dennis

von Peter II (Gast)


Lesenswert?

Dennis S. schrieb:
> Frage: warum funktioniert das?

warum sollte das nicht funktionieren?

Er nimmt einfach für jedes % das nächste Element auf dem Stack. Ob sie 
vorher dort abgelegt wurden spielt dabei keine rolle.

von Dennis S. (eltio)


Lesenswert?

Peter II schrieb:
> warum sollte das nicht funktionieren?
Warum sollte es? Wenn ich nichts zum Ausgeben angebe, könnte es ja auch 
sein, dass nichts ausgegeben wird.

> Er nimmt einfach für jedes % das nächste Element auf dem Stack. Ob sie
> vorher dort abgelegt wurden spielt dabei keine rolle.
Danke, das ist eine Erklärung.

von Peter II (Gast)


Lesenswert?

Dennis S. schrieb:
>> warum sollte das nicht funktionieren?
> Warum sollte es? Wenn ich nichts zum Ausgeben angebe, könnte es ja auch
> sein, dass nichts ausgegeben wird.

leider gibt es für solche Funktionen keine Möglichkeit zu prüfen, wie 
viele Elemente übergeben wurden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Er nimmt einfach für jedes % das nächste Element auf dem Stack.

Allgemeiner: er nimmt das nächste Argument irgendwoher.

Auf einer Architektur mit Speicherverwaltung könnte das ggf. auch
einen Trap auslösen (weil auf Speicher zugegriffen wird, der nicht
gemappt ist), aber ansonsten gibt das halt was aus, ohne dass man
irgendwie vorhersagen kann, was es wirklich ausgibt.  Ist also
eher eine wertlose Aussage …

von Jobst Q. (joquis)


Lesenswert?

Das funktioniert nur, solange es in der letzten Funktion des Programms 
geschieht. Es holt mehr Argumente vom Stack als vorher draufgelegt 
wurden, die Probleme damit hätten die folgenden Funktionen.

von Peter II (Gast)


Lesenswert?

Jobst Quis schrieb:
> Das funktioniert nur, solange es in der letzten Funktion des Programms
> geschieht. Es holt mehr Argumente vom Stack als vorher draufgelegt
> wurden, die Probleme damit hätten die folgenden Funktionen.

nein, denn bei cdecl räumt der Aufrufe der Stack wieder auf und diese 
kennt ja die Paramter.

http://de.wikipedia.org/wiki/Aufrufkonvention#stdcall

von Karl H. (kbuchegg)


Lesenswert?

Ich würde mal sagen:
Ob das 'funktioniert' oder nicht, hängt davon ab, was man als 
'funktioniert' definiert.
Gibt man sich mit irgendeinem Ergebnis zufrieden, dann kann man das 
'funktioniert' nennen.

Garantie gibt es dafür keine. In keiner irgendwie definierten Form.

C an sich kennt noch nicht mal einen Stack. Ein Stack ist etwas, was die 
meisten Plattformen benutzen. Aber in der kompletten Sprachdefinition 
wird an keiner Stelle ein Stack erwähnt oder gefordert.

Interessant wäre höchstens, worum es im Kontext dieses präsentierten 
Code-Schnipsels im Buch überhaupt geht. WEnn das dort als abschreckendes 
Beispiel benutzt wird, wie man es nicht macht, dann ist das ok. Aber auf 
keinen Fall kann das ein Beispiel für auch nur entfernt sinnvolles 
programmieren sein. Vor allen Dingen nicht in einem Buch mit dem Titel 
"Writing Secure Code".

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Ich würde mal sagen:
> Ob das 'funktioniert' oder nicht, hängt davon ab, was man als
> 'funktioniert' definiert.
> Gibt man sich mit irgendeinem Ergebnis zufrieden, dann kann man das
> 'funktioniert' nennen.
>
> Garantie gibt es dafür keine. In keiner irgendwie definierten Form.

Steht so aucj in der *printf Dokumentation.

Und je nach System funktioniert das auch nicht sondern ergibt einen 
Segmentation Fault o.ä., und wenn ich mal mehr%-Argumente hab als 
Parameter dann ist "funktionieren" die absolute Ausnahme.

Übrigens ist "View the Stack" ziemlicher Unsinn, weil es Vorsausetzungen 
an das Hostsystem und die Calling-Convention macht, die i.d.R nicht 
zutreffen.

Ergo:  Das Buch / Tutorial das bereits bei so elementaren Dingen Käse 
verzapft gehört in die Tonne!

So ein Hum-Buch schadet mehr als es nützt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
> Ergo:  Das Buch / Tutorial das bereits bei so elementaren Dingen Käse
> verzapft gehört in die Tonne!

Dennis S. schrieb:
> in dem Buch "Writing Secure Code"

Vermutlich soll darin das Prinzip von Buffer-Overrun-Attacken
demonstriert werden. Mit dem seltsamen Printf können – wenn auch nicht
zuverlässig – Dinge auf dem Stack sichtbar gemacht werden, die dort
nicht hingehören.

: Bearbeitet durch Moderator
von Mark B. (markbrandis)


Lesenswert?

Karl Heinz schrieb:
> C an sich kennt noch nicht mal einen Stack.

Huch?

Aber der vom C-Compiler generierte x86 Assembler- bzw. Maschinencode 
schon, oder?

von Karl H. (kbuchegg)


Lesenswert?

Mark Brandis schrieb:
> Karl Heinz schrieb:
>> C an sich kennt noch nicht mal einen Stack.
>
> Huch?
>
> Aber der vom C-Compiler generierte x86 Assembler- bzw. Maschinencode
> schon, oder?

Natürlich.
Irgendwie muss ja der Compiler die geforderte Funktionalität ja auch 
umsetzen. Aber der C-Standard lässt ihm da volle Freiheit, wie er das zu 
tun gedenkt. Stack ist da nicht gefordert.
Auch die Verwendung von 2-er Komplement ist kein muss.
Selbst der Zeichensatz ist weitgehend nicht definiert. Es gibt lediglich 
eine Aufzählung, welche Zeichen mindestens vorhanden sein müssen und das 
die Zeichen '0' bis '9' aufsteigende, aufeinanderfolgende Codes haben 
müssen. Alles andere, wie die Verwendung von ASCII ist freigestellt.
Auch der Begriff 'Heap' kommt im Standard nicht vor.
Genauso wie es keinen Bildschirm oder gar eine Tastatur gibt.
...

Es sind ziemlich viele Dinge, die im C Standard nicht reglementiert 
sind. ALs Faustregel könnte man sagen: Wenn etwas auch nur im 
entferntesten hardwareabhängig ist, dann macht der C-Standard da einen 
Bogen drum herum. Das war/ist einerseits einer der Gründe für den Erfolg 
von C, ist aber andererseits aber auch wieder ein Nachteil.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Johann L. schrieb:
>> Ergo:  Das Buch / Tutorial das bereits bei so elementaren Dingen Käse
>> verzapft gehört in die Tonne!
>
> Dennis S. schrieb:
>> in dem Buch "Writing Secure Code"
>
> Vermutlich soll darin das Prinzip von Buffer-Overrun-Attacken
> demonstriert werden.

Ok.  In dem Beispiel bekommt man immerhin eine Warnung vom Compiler.

Übler ist folgender Lapsus:
1
void print_text_from_user (const char *text)
2
{
3
    printf (text);
4
}

Korrekt ist
1
printf ("%s", text);
bzw.
1
fputs (text, stdout);

von Bastler (Gast)


Lesenswert?

Es gibt auch SPARC, da werden Register-Fenster umgeschaltet beim Call.
Oder /360..390, die hat keinen dedizierten Stack, aber jede Menge 
Register, die als Index-Register taugen. Da gibt es auch kein CALL 
sondern BranchAndLoadRegister. Ein Stack entsteht als verkettete Liste. 
R0 zeigt auf ein Array aus Pointern auf die Parameter. Übergebe ich nur 
den FormatString, dann zeigen die "folgenden Parameter" schlicht ins 
Nirvana.

von Dennis S. (eltio)


Lesenswert?

Zum Teil interessante Anmerkungen. Aber wie emotional manche plötzlich 
werden ist wirklich... unverständlich.

Der Codeschnippsel ist eine Demonstration eines Stack-Overruns. Da das 
Buch im Microsoft Press-Verlag erschienen ist, kann man die 
Umgebungsbedingungen eigentlich schon recht klar definiert. Ich muss 
aber dazu sagen, dass ich es bisher nur überflogen habe.

von Mark 99 (Gast)


Lesenswert?

Dennis S. schrieb:
> Da das
> Buch im Microsoft Press-Verlag erschienen ist,

Das erklärt den Scheiß --> Tonne.

Die Welt besteht aus mehr als nur Microsoft, und im Embedded-Bereich 
(Tipp: Wie heißt dieses Seite nochmal?) spielt Microsoft keine Rolle.

von Peter II (Gast)


Lesenswert?

Mark 99 schrieb:
> Das erklärt den Scheiß --> Tonne.
>
> Die Welt besteht aus mehr als nur Microsoft, und im Embedded-Bereich
> (Tipp: Wie heißt dieses Seite nochmal?) spielt Microsoft keine Rolle.

unter gcc funktioniert das Beispiel und wir sind hier im GCC Forum.

von Dennis S. (eltio)


Lesenswert?

Mark 99 schrieb:
> Das erklärt den Scheiß --> Tonne.
Der Auszug ist das passende Werkzeug für die passende Aufgabe oder 
nicht? Hast du mehr Beispiele aus dem Buch, die nicht angemessen sind?

> Die Welt besteht aus mehr als nur Microsoft, und im Embedded-Bereich
> (Tipp: Wie heißt dieses Seite nochmal?) spielt Microsoft keine Rolle.
Hmm.. das haben meine Linux-Rechner mir gar nicht verraten. Aber: Mea 
Culpa, ich war im falschen Unterforum.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> unter gcc funktioniert das Beispiel

Nochmal: das macht irgendwas.  Mit GCC auf einer UltraSPARC ist
keineswegs sicher, dass da irgendwas vom Stack angezeigt wird, denn
dort werden auch bei varargs die Argumente zuerst im entsprechenden
Registerfenster übergeben; der Stack wird dort nur für Funktionen
mit sehr vielen Argumenten genutzt.

Es gäbe weiß Gott genügend Beispiele aus der Praxis, an denen man
real vorhandene (und ausnutzbare) Stack-Attacken demonstrieren kann.
Klar, diese Teile sind immer auf eine bestimmte Architektur
zugeschnitten, denn in aller Regel möchte man erreichen, dass
Fremdcode (des Attackierenden) ausgeführt wird, bspw. indem man
diesen als Maschinencode auf den Stack packt und durch gezieltes
Überschreiben der Rücksprungadresse dann einen Sprung auf diesen
Code provoziert.

von Peter II (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Nochmal: das macht irgendwas.

es steht nicht da das der code portable ist, aber in 99% der üblichen 
Hard und Software macht es das was im Kommentar steht.

von Peter II (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Mit GCC auf einer UltraSPARC ist
> keineswegs sicher, dass da irgendwas vom Stack angezeigt wird, denn
> dort werden auch bei varargs die Argumente zuerst im entsprechenden
> Registerfenster übergeben; der Stack wird dort nur für Funktionen
> mit sehr vielen Argumenten genutzt.

dann scheint die Doku von GCC aber falsch zu sein.

https://gcc.gnu.org/onlinedocs/gccint/Varargs.html
— Macro: __builtin_next_arg (lastarg)
This builtin returns the address of the first anonymous stack argument, 
as type void *. If ARGS_GROW_DOWNWARD, it returns the address of the 
location above the first anonymous stack argument. Use it in va_start to 
initialize the pointer for fetching arguments from the stack. Also use 
it in va_start to verify that the second parameter lastarg is the last 
named argument of the current function.


hier ist "first anonymous stack Argument" geschrieben, also wird es wohl 
immer über den stack laufen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter II schrieb:
> hier ist "first anonymous stack Argument" geschrieben, also wird es wohl
> immer über den stack laufen.

Wenn aber die Maschine gar keinen Stack hat, wie Jörgs SPARC? Da wird 
dann wohl die ABI anders aussehen, und die Funktion was anderes machen, 
bzw. den Begriff "Stack" eher als Metabegriff auslegen.

von Peter II (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wenn aber die Maschine gar keinen Stack hat, wie Jörgs SPARC? Da wird
> dann wohl die ABI anders aussehen,
die Doku ist aber von GCC und von keiner speziellen Platform

> und die Funktion was anderes machen,
> bzw. den Begriff "Stack" eher als Metabegriff auslegen.
dann kann man auch den Begriff "Stack" von dem code als Metabegriff 
sehen und er macht wieder das was im Kommentar steht.

von Markus F. (mfro)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wenn aber die Maschine gar keinen Stack hat, wie Jörgs SPARC?

SPARC-Maschinen haben durchaus einen Stack und auch ein "SP"-Register. 
In "altmodischer Denkweise" könnte man sogar sagen: bis zu 32 davon...

Aber mal ernsthaft: wer hätte von einem Microsoft-Press Buch erwartet, 
daß es da drin irgendwas anderes als x86 zu lesen gäbe?

: Bearbeitet durch User
von Michl (Gast)


Lesenswert?

Markus F. schrieb:
> Aber mal ernsthaft: wer hätte von einem Microsoft-Press Buch erwartet,
> daß es da drin irgendwas anderes als x86 zu lesen gäbe?

Ich glaube hier geht es grad eher darum, dass mit zweierlei Maß gemessen 
wird.
Der Autor des obigen Codes wird dafür kritisiert dass der Code 
plattformspzifisch ist und der Begriff "Stack" im Kommentar verwendet 
wird, wo doch garnicht alle Architekturen einen Stack kennen.

Der gcc-Doku wird die Verwendung dieses Begriffes aber nachgesehen...

von va (Gast)


Lesenswert?

Macro: __builtin_saveregs ()

    Use this built-in function to save the argument registers in memory 
so that the varargs mechanism can access them.
Both ISO and traditional versions of va_start must use 
__builtin_saveregs

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michl schrieb:
> Der Autor des obigen Codes wird dafür kritisiert dass der Code
> plattformspzifisch ist und der Begriff "Stack" im Kommentar verwendet
> wird, wo doch garnicht alle Architekturen einen Stack kennen.

So ziemlich alle Architekturen kennen einen Stack. Der wird aber nicht 
auf allen Architekturen vollständig für Funktionsargumente benutzt, 
siehe SPARC.

> Der gcc-Doku wird die Verwendung dieses Begriffes aber nachgesehen...

Du wirfst da was durcheinander: Bei der Sprachdefinition von C braucht 
man den Begriff "Stack" tatsächlich nicht.

gcc jedoch ist das "Werkzeug" - nicht die Sprache. gcc bedient sich halt 
im konkreten Fall eines Stacks, um Argumente zu übergeben. Aber das ist 
nur eine konkrete Implementierung - nichts weiter.

: Bearbeitet durch Moderator
von Tom (Gast)


Lesenswert?

Bevor jetzt alle unnötig weiterpöbeln: OP hat das Beispiel aus dem Buch 
auf das für seine Frage wesentliche (nämlich das printf ohne Argumente) 
gekürzt.

Der Stack wird in dem eigentlichen Beispiel klassisch mit (sinngemäß) 
strcopy(buffer, argv[1]) überschrieben und die Zusammenhänge erklärt. 
Mit einem 2002 aktuellen VS hat das ganze wahrscheinlich auch 
funktioniert.

Zu erwarten, dass Exploits portabel sein sollen, ist vielleicht etwas 
übertrieben.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Michl schrieb:
> Der gcc-Doku wird die Verwendung dieses Begriffes aber nachgesehen...

Du vergisst dabei, dass es sich hier nicht um die Benutzer-Doku
des GCC handelt, sondern um die interne, die sich also an
Entwickler richtet, die selbst mit dem GCC arbeiten.

Aus Nutzersicht (also aus der des C-Standards) gibt es keine
Verpflichtung für einen Stack.

Aus Implementierungssicht (Entwickler) haben die meisten (wenn nicht
gar alle) Maschinen, auf die GCC portiert ist, sicherlich einen solchen.

Übrigens hat Peter da ganz großzügig die Überschrift weggelassen, die
über all dem, was er zitiert hat, drüber steht:
1
GCC comes with an implementation of <varargs.h> and <stdarg.h> that 
2
work without change on machines that pass arguments on the stack. Other 
3
machines require their own implementations of varargs, and the two 
4
machine independent header files must have conditionals to include it.

Damit ist also völlig klar, dass es Maschinen geben kann, für die diese
dort dokumentierten Makros nicht existieren.

Back to topic: auch, wenn das Ding auf vielen gängigen Maschinen
irgendeinen Teil des Stacks ausgeben wird, was genau will man damit?
Ohne exakte Kentniss der Details der jeweiligen Maschine kann man
damit rein gar nichts explizit sagen, es ist noch nicht einmal klar,
ob beispielsweise die Rückkehradresse der aktuellen Funktion mit
in dem angezeigten Datenmüll ist oder nicht.

von KLaus (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Back to topic: auch, wenn das Ding auf vielen gängigen Maschinen
> irgendeinen Teil des Stacks ausgeben wird, was genau will man damit?

Nachschauen, ob der Schadcode, den er eingeschleust hat, auch richtig 
angekommen ist ;)

MfG Klaus

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang noch der komplette Code, der (zusammen mit einigen Seiten 
Erklärung, für die sich jeder selbst das Buch zulegen darf) lediglich 
das Prinzip des Bugs an einem nachvollziehbaren Mickey-Maus-Beispiel 
erklärt. Die Zielgruppe des Buchs hatte natürlich Windows und VS6.0 und 
konnte sehr wahrscheinlich die dokumentierten Schritte nachvollziehen, 
um anhand der Ausgaben das Argument herauszufinden, das nötig ist, um 
sich selbst zu hacken und bar() aufrufen. Wenn sich hinterher der Leser 
gemerkt hat, dass sehr seltsame Dinge passieren können, wenn man 
statische Buffer überlaufen lässt, war das Ziel des Kapitels erreicht; 
ob der Code mit einem obskuren Compiler auf einer obskuren 
Rechnerarchitektur unter einem obskuren Betriebssystem auch liefe, war 
dem Autor natürlich völlig egal.

von Rolf M. (rmagnus)


Lesenswert?

Mark 99 schrieb:
> Dennis S. schrieb:
>> Da das
>> Buch im Microsoft Press-Verlag erschienen ist,
>
> Das erklärt den Scheiß --> Tonne.

Es geht um die Erklärung von Sicherheitslücken und hier speziell Stack 
Overruns. Selbstverständlich ist das immer systemspezifisch. Nirgends 
wurde behauptet, daß es sich um ein Buch über ISO C handelt. Ist für 
dich ein Buch über AVR-Programmierung auch für die Tonne, weil da drin 
steht, wie man I/O-Ports anspricht und den ADC konfiguriert? Das ist nun 
mal systemspezifisch.

Frank M. schrieb:
> So ziemlich alle Architekturen kennen einen Stack. Der wird aber nicht
> auf allen Architekturen vollständig für Funktionsargumente benutzt,
> siehe SPARC.
>
>> Der gcc-Doku wird die Verwendung dieses Begriffes aber nachgesehen...
>
> Du wirfst da was durcheinander: Bei der Sprachdefinition von C braucht
> man den Begriff "Stack" tatsächlich nicht.

Dieses Buch hat doch gar nicht die Aufgabe, die Sprache C definieren.

von Dennis S. (eltio)


Lesenswert?

Tom schrieb:
> Im Anhang noch der komplette Code, der (zusammen mit einigen Seiten
> Erklärung, für die sich jeder selbst das Buch zulegen darf) lediglich
> das Prinzip des Bugs an einem nachvollziehbaren Mickey-Maus-Beispiel
> erklärt. Die Zielgruppe des Buchs hatte natürlich Windows und VS6.0 und
> konnte sehr wahrscheinlich die dokumentierten Schritte nachvollziehen,
> um anhand der Ausgaben das Argument herauszufinden, das nötig ist, um
> sich selbst zu hacken und bar() aufrufen. Wenn sich hinterher der Leser
> gemerkt hat, dass sehr seltsame Dinge passieren können, wenn man
> statische Buffer überlaufen lässt, war das Ziel des Kapitels erreicht;
> ob der Code mit einem obskuren Compiler auf einer obskuren
> Rechnerarchitektur unter einem obskuren Betriebssystem auch liefe, war
> dem Autor natürlich völlig egal.

Danke, ich war zu faul das zu schreiben, weil die Diskussion schon so 
weit vom Kern des Themas entfernt war...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Dieses Buch hat doch gar nicht die Aufgabe, die Sprache C definieren.

Habe ich auch nirgendwo behauptet. Es ging um den "Vorwurf", dass die 
gcc-Dokumentation sehr wohl von einem Stack plappert, obwohl dieser gar 
nicht Umfang der Sprache ist.

Bitte sorgfältiger lesen. Danke.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tom schrieb:
> Im Anhang noch der komplette Code, der (zusammen mit einigen Seiten
> Erklärung, für die sich jeder selbst das Buch zulegen darf) lediglich
> das Prinzip des Bugs an einem nachvollziehbaren Mickey-Maus-Beispiel
> erklärt.

Als geschlossenes Beispiel hat das natürlich schon deutlich mehr
Sinn, ja.

von Rolf M. (rmagnus)


Lesenswert?

Frank M. schrieb:
> Rolf Magnus schrieb:
>> Dieses Buch hat doch gar nicht die Aufgabe, die Sprache C definieren.
>
> Habe ich auch nirgendwo behauptet. Es ging um den "Vorwurf", dass die
> gcc-Dokumentation sehr wohl von einem Stack plappert, obwohl dieser gar
> nicht Umfang der Sprache ist.

Du verteidigst aber oben den Vorwurf gegen das Buch. Zumindest kann man 
das da rauslesen.

> Bitte sorgfältiger lesen. Danke.

Bitte sorgfältiger schreiben. Danke.

von Jobst Q. (joquis)


Lesenswert?

Peter II schrieb:
> Jobst Quis schrieb:
>> Das funktioniert nur, solange es in der letzten Funktion des Programms
>> geschieht. Es holt mehr Argumente vom Stack als vorher draufgelegt
>> wurden, die Probleme damit hätten die folgenden Funktionen.
>
> nein, denn bei cdecl räumt der Aufrufe der Stack wieder auf und diese
> kennt ja die Paramter.
>
> http://de.wikipedia.org/wiki/Aufrufkonvention#stdcall

Aber das Aufräumen geschieht nach der Anzahl der Parameter und nicht 
durch Interpretation des Formatstrings. Bei einem konstanten 
Formatstring wäre das dem Compiler ja theoretisch noch möglich, aber er 
muss ja nicht konstant sein.

 Wenn ich mal bei printf einen Parameter vergesse, kommt prompt ein 
"Segmentation Fault" oder ähnliches.

Und ohne cdecl-Aufrufkonvention wäre eine Funktion mit variabler 
Parameterzahl garnicht möglich.

von meckerziege (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wenn aber die Maschine gar keinen Stack hat, wie Jörgs SPARC? Da wird
> dann wohl die ABI anders aussehen, und die Funktion was anderes machen,
> bzw. den Begriff "Stack" eher als Metabegriff auslegen.

Der Vollständigkeit halber: Bei SPARC werden die ersten 6 Parameter über 
Register übergeben (%i0 bis %i5 bzw. %o0 bis %o5). Alles was darüber 
hinausgeht kommt auf den Stack. Aber nicht direkt am Stackpointer (ja, 
es gibt auch hier einen Stack!), sondern mit ein wenig Abstand (genau 
sagt kommen dazwischen nochmal unter anderem 16 Words Platz für das 
Sichern der Registerwindow-Inhalte, für den Fall, dass die Register 
Windows alle bereits benutzt werden).
Alles nachzulesen im SPARC ABI.

Wenn nun aber der Code mit -mflat kompiliert wurde, dann sieht die Sache 
wieder anders aus, da keine Register Windows verwendet werden.

Es ist also nicht nur abhängig vom Prozessor sondern auch von den 
Einstellungen beim Kompilieren und noch einigen anderen Punkten.
Kurz gesagt: Es kommt irgendwas raus, einen Sinn macht es nicht 
unbedingt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

meckerziege schrieb:
> Der Vollständigkeit halber: Bei SPARC werden die ersten 6 Parameter über
> Register übergeben

Yep, dass nur die ersten N Parameter in Registern übergeben werden,
schrieb ich oben schon.  Ich wusste nur nicht mehr aus dem Kopf, wie
groß N genau ist.

Im Gegensatz beispielsweise zum AVR-GCC passiert das dort auch für
variable Argumentlisten.  Der AVR-GCC übergibt zwar normalerweise
auch viele Parameter in Registern, aber bei varargs verfällt er
sofort auf den Stack.

von Markus F. (mfro)


Lesenswert?

Jobst Quis schrieb:
> Aber das Aufräumen geschieht nach der Anzahl der Parameter und nicht
> durch Interpretation des Formatstrings. Bei einem konstanten
> Formatstring wäre das dem Compiler ja theoretisch noch möglich, aber er
> muss ja nicht konstant sein.

Das wär' ja auch 'ne mittlere Katastrophe.

Beim Aufräumen müssen natürlich genau die Parameter wieder runter vom 
Stack, die vorher draufgelegt wurden (und nicht irgendwelche, die 
irgendwie im Formatstring stehen).

Und wenn der Aufrufer nicht weiß, wieviele und welche Parameter das 
sind, wer dann?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Im Gegensatz beispielsweise zum AVR-GCC passiert das dort auch für
> variable Argumentlisten.  Der AVR-GCC übergibt zwar normalerweise
> auch viele Parameter in Registern, aber bei varargs verfällt er
> sofort auf den Stack.

Naja, das kann man eben nicht einfach ändern...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Naja, das kann man eben nicht einfach ändern...

Ist mir schon klar.  War auch keine Kritik (jenseits von printf und
seinen Derivaten braucht man varargs ja ohnehin eher selten), sondern
sollte nur beschreiben, dass es da eben auch zwischen den verschiedenen
GCC-Plattformen zuweilen krätige Unterschiede gibt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Naja, so unterschiedlich wie ABIs eben sein können.

Peter II schrieb:
> dann scheint die Doku von GCC aber falsch zu sein.
>
> https://gcc.gnu.org/onlinedocs/gccint/Varargs.html
> — Macro: __builtin_next_arg (lastarg)
> This builtin returns the address of the first anonymous stack argument,

Das ist nicht aus der GCC-Doku sondern aus den Internals.  Je nach ABI 
können (system)Bibliotheken dies verwenden um stdarg bzw. 
Hilfsfunktionen dafür etc. zu implementieren.  Siehe die zig anderen 
Targte-Makros und Expander zur stdarg-Implementierung.  Das muss schon 
alles zusammenpassen, einfach blind Features aus den Internals verwenden 
ist keine gute Idee, z.B. auch für nur intern zu verwendende 
Constraints.

Für den "normalen" Anwender ist dieses Built-in also nicht gedacht und 
auch nicht in der GCC-Doku bei den Built-ins gelistet.

von Eric B. (beric)


Lesenswert?

Dennis S. schrieb:
> Hallo zusammen,
> in dem Buch "Writing Secure Code" habe ich einen Quellcode in der
> folgenden Art gefunden:
>
>
1
> #include <stdio.h>
2
> 
3
> void foo(void) {
4
>   int x, y;
5
>         /* View the stack */
6
>   printf("My Stack: \n%p\n%p\n%p\n%p\n%p\n%p\n\n");
7
> }
8
>

Schmeiss bitte das Buch weg oder verbrenne es! Der printf in "foo()" 
corrumpiert möglicherweise den Stack und das hat mit "Secure Code" 
nichts zu tun. Es sei denn dies wäre ein Beispiel wie man nicht 
programmieren soll...

von Peter II (Gast)


Lesenswert?

Eric B. schrieb:
> Der printf in "foo()"
> corrumpiert möglicherweise den Stack und das hat mit "Secure Code"
> nichts zu tun.

nein macht er bestimmt nicht, da er nur lesend zugreift.

von Dennis S. (eltio)


Lesenswert?

Eric B. schrieb:
> Schmeiss bitte das Buch weg oder verbrenne es! Der printf in "foo()"
> corrumpiert möglicherweise den Stack und das hat mit "Secure Code"
> nichts zu tun. Es sei denn dies wäre ein Beispiel wie man /nicht/
> programmieren soll...

Du hast nur die Hälfte mitbekommen... Siehe die schöne Zusammenfassung 
von
Autor: Tom (Gast)
Datum: 14.11.2014 11:43

Gruß
Dennis

von Bronco (Gast)


Lesenswert?

Dennis S. schrieb:
> Frage: warum funktioniert das?

Hallo Dennis,

ich hab den Eindruck, dass Deine eigentliche Frage noch gar nicht 
richtig beantwortet wurde:
Bei variadischen Funktionen (Funktionen mit variabler Anzahl an 
Argumenten) ist beim Compilieren nicht bekannt bzw. festgelegt, welche 
und wieviele Daten übergeben werden. Aus diesen Grund werden die Daten 
in Form einer Liste von "int" übergeben, und diese Liste liegt nicht 
selten auf dem Stack.

Beim Aufruf von
1
printf("My Stack: \n%p\n%p\n%p\n%p\n%p\n%p\n\n");
passiert nun folgendes:
Der Formatstring sagt aus, daß dem printf 6 Argument übergeben wurden, 
obwohl in Wirklich kein Argument übergeben wurde.
Printf holt sich also die vermeindlichen 6 Argumente vom Stack, und 
zeigt sie an. Da aber gar keine Argumente übergeben wurde, wird das 
angezeigt, was vorher schon auf dem Stack gelegen hat.
Jenachdem ob da überhaupt etwas liegt, kann es einen Speicherfehler 
heben.

von Karl H. (kbuchegg)


Lesenswert?

Bronco schrieb:

> ich hab den Eindruck, dass Deine eigentliche Frage noch gar nicht
> richtig beantwortet wurde:

Doch, das ist alles schon gesagt worden.
Auch das es in C gar keinen Stack geben muss, von dem sich printf die 
Werte holt.

von Dennis S. (eltio)


Lesenswert?

Bronco schrieb:
> Hallo Dennis,
>
> ich hab den Eindruck, dass Deine eigentliche Frage noch gar nicht
> richtig beantwortet wurde:
> Bei variadischen Funktionen (Funktionen mit variabler Anzahl an
> Argumenten) ist beim Compilieren nicht bekannt bzw. festgelegt, welche
> und wieviele Daten übergeben werden. Aus diesen Grund werden die Daten
> in Form einer Liste von "int" übergeben, und diese Liste liegt nicht
> selten auf dem Stack.
>
> Beim Aufruf vonprintf("My Stack: \n%p\n%p\n%p\n%p\n%p\n%p\n\n");
> passiert nun folgendes:
> Der Formatstring sagt aus, daß dem printf 6 Argument übergeben wurden,
> obwohl in Wirklich kein Argument übergeben wurde.
> Printf holt sich also die vermeindlichen 6 Argumente vom Stack, und
> zeigt sie an. Da aber gar keine Argumente übergeben wurde, wird das
> angezeigt, was vorher schon auf dem Stack gelegen hat.
> Jenachdem ob da überhaupt etwas liegt, kann es einen Speicherfehler
> heben.

Mir ist das schon klar gewesen, aber dennoch danke für deine Mühe! :-) 
Ich hatte mich etwas aus der Diskussion zurückzogen, weil die 
angesprochenen "Spezialfälle" für mich nicht relevant sind.

Gruß
Dennis

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.