(erledigt)[C++]struct auf zu kleinem Puffer standardkonform?

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

dot hat geschrieben:
Krishty hat geschrieben:memcpy() ist zwar nicht mehr soo viel Overhead, weil es fast alle Compiler zu einem einzelnen Load optimieren würden, aber es verschwendet noch immer Speicher auf dem Stack und verhindert die Nutzung kurzer Befehle. (Aus add rax, word ptr [file + 8] würde mov word ptr [rsp+60], word ptr [file + 8] / add rax, word ptr [rsp+60] weil du nun eine Variable hast, deren Adresse beschrieben wird.)
Also clang macht mir aus beiden Varianten den exakt selben Machinencode... ;)
Cool, danke! Da pennt Visual C++ also mal wieder.
Und was die Quälerei angeht:
Neee – ich greife nicht seriell auf die Daten zu. Ich brauche echten wahlfreien Zugriff! Ich müsste alles in lokalen Variablen fetchen, in der richtigen Reihenfolge, aber dann habe ich 30 davon und keinen Mehrwert gegenüber einem struct-Overlay.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

DerAlbi hat geschrieben:a) oder ist struct->int ailiasing mit IntArray[n] erlaubt, weils beides int sind ?)
Puh, keine Ahnung. VIELLEICHT wäre es mit POD erlaubt, aber … uff.
DerAlbi hat geschrieben:b) struct->int ailiasing mit floatArray[n] ist nicht erlaubt, aber fürde ich den float als char* aus dem Speicher binär zusammensetzen ist das ok? (immernoch: wtf)
Ja, ist es. Ist der einzig portable Weg, float als int zu interpretieren (LOL). Bedenk, dass sich das aber einfacher als memcpy() ausdrücken lässt, weil das intern immer auf char * operiert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von DerAlbi »

*_* Danke <3
:-D
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

Krishty hat geschrieben:Neee – ich greife nicht seriell auf die Daten zu. Ich brauche echten wahlfreien Zugriff! Ich müsste alles in lokalen Variablen fetchen, in der richtigen Reihenfolge, aber dann habe ich 30 davon und keinen Mehrwert gegenüber einem struct-Overlay.
Naja, im Gegensatz zu einem struct-Overlay wäre es portabel... ;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

Wo ist das struct nicht portabel?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

struct Layout ist im Allgemeinen nicht portabel... ;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

Praktisch ist’s portabel genug.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

Krishty hat geschrieben:Die Casts sind also gültig und jede Operation, die ich auf S * durchführe, spiegelt sich auch mit Strict Aliasing in jedem char * wieder.
Das Problem sind ja auch nicht die Pointercasts (sofern man mal davon ausgeht, dass alle involvierten Typen kompatible Alignment Requirements haben), sondern was du mit dem gewonnenen Pointer dann anstellst. Du darfst eben nur über einen aus char* (oder void*, das macht hier eigentlich keinen Unterschied) gewonnenen S* auf ein S an dieser Stelle zugreifen, wenn sich dort tatsächlich ein S befindet. Ein S befindet sich dort nur, wenn zuvor dort ein S konstruiert wurde...

Die Lösung per memcpy() funktioniert, weil es sich um trivially-copyable Types handelt und der Standard mir garantiert, dass ich die sizeof(T) Bytes der Object-Representation eines trivially-copyable Type T aus einem existierenden T rauskopieren darf und, sobald ich sie wieder in ein T hineinkopiere, dieses dann das Value des ursprünglichen T hat...
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

Das S wurde in der Tat dort konstruiert, nur eben nicht während der Laufzeit des Prozesses ;)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

Krishty hat geschrieben:Das S wurde in der Tat dort konstruiert, nur eben nicht während der Laufzeit des Prozesses ;)
Jo, das ist mir schon klar, auch dass das alles so funktionieren wird. Nur nach meiner Leseart des Standard müsste das streng genommen dennoch UB sein und man kann leider nicht wirklich was dran ändern (malloc() + Cast müsste imo btw auch UB sein)... ;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

malloc() & Cast dürfte sogar recht sicher UB sein, so lange man kein Placement new drauf durchführt. In C hingegen ist das (natürlich) völlig legal, also benenne ich im Zweifel die Quelldatei der Parsing-Funktion in foo.c um :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

Krishty hat geschrieben:[...]also benenne ich im Zweifel die Quelldatei der Parsing-Funktion in foo.c um :)
Das sollte in der Tat eine gültige Lösung sein...xD
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von CodingCat »

Krishty hat geschrieben:malloc() & Cast dürfte sogar recht sicher UB sein, so lange man kein Placement new drauf durchführt. In C hingegen ist das (natürlich) völlig legal, also benenne ich im Zweifel die Quelldatei der Parsing-Funktion in foo.c um :)
Nah, (§3.8) Object Lifetime beginnt wenn Speicherplatz mit korrektem Alignment für Typ T da ist, und [Initialisierung vollständig durchgeführt ODER trivial] ist. malloc kümmert sich für alle fundamentalen Typen T und Aggretates davon um korrektes Alignment, ergo funktioniert das mit dem Cast schon und der dynamische Typ T des Objekts steht fest, sobald Speicher durch den Cast mit diesem in Verbindung gebracht wird. Für nicht-triviale Typen muss der Cast logischerweise durch ein Placement-New zur vollständigen Initialisierung/Konstruktion ersetzt werden.

Das beantwortet auch die Eingangsfrage, sofern der Speicher aus deiner Datei das richtige Alignment UND die richtige Größe hat, ist alles in Ordnung. Letzteres ist offensichtlich manchmal verletzt. Der Compiler könnte z.B. beide Loads zusammenfassen und aus dem if ziehen, sobald nach dem ersten Zugriff klar ist, dass ein gültiges Objekt vorliegen muss; was er vermutlich nie tun wird, aber darum geht es bei der Frage nach undefiniertem Verhalten ja nicht. Das mit dem memcpy ist übrigens auch unnötig, §3.10.10 erlaubt explizit auch Aliasing durch Elemente von glvalues (Zeiger/Referenzen) von Aggregates oder Unions. §9.2.19 garantiert außerdem, dass ein Zeiger auf ein struct-Objekt immer auch auf das erste Element zeigt. Insofern wäre es z.B. möglich, die verschiedenen Varianten mit geschachtelten structs umzusetzen, wobei die innerste Struktur den kleinstmöglichen Header darstellt, und dann von optional ausführlicheren Header-Strukturen als geschachteltes Element an erster Stelle eingebunden wird, SOFERN dem Compiler z.B. durch non-standard Extensions das richtige Padding der enthaltenen Strukturen aufgezwungen wird (soll heißen, das Padding mit dem die Datei erstellt wurde). Das Padding-Problem gilt natürlich generell für structs - nicht nur für die Endbytes von geschachtelten; auch zwischen den Elementen.

Fazit: Sobald Größe, Alignment, Padding und damit die Byte-Repräsentation stimmt, existieren nach §3.8 erstmal alle potentiellen trivialen Objekte, die dort hinein passen, insbesondere auch das größtmögliche aggregierte.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

Ah, hab §3.8 übersehen, das ist natürlich nice, damit ist die Sache wohldefiniert; thx für den Hinweis, jetzt kann ich gleich viel besser schlafen... :D
Benutzeravatar
Krishty
Establishment
Beiträge: 8240
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von Krishty »

Napf Brekkies für meine Lieblingskatze

Bild

dot, erledigt das auch, womit wir im letzten Thread aneinandergeraten sind?
dot hat geschrieben:
Krishty hat geschrieben:Und ein Haufen von nicht-konstruierten Objekten macht halt *doch* Sinn, wenn es sich um POD handelt :)
Nö, ein Haufen von nicht-konstruierten POD Objekten macht genauso keinen Sinn, denn nicht-konstruierte Objekte existieren per Definition nicht, egal wie P oder O der T auch noch sein mag... :P
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[C++]struct auf zu kleinem Puffer standardkonf

Beitrag von dot »

Krishty hat geschrieben:dot, erledigt das auch, womit wir im letzten Thread aneinandergeraten sind?
dot hat geschrieben:
Krishty hat geschrieben:Und ein Haufen von nicht-konstruierten Objekten macht halt *doch* Sinn, wenn es sich um POD handelt :)
Nö, ein Haufen von nicht-konstruierten POD Objekten macht genauso keinen Sinn, denn nicht-konstruierte Objekte existieren per Definition nicht, egal wie P oder O der T auch noch sein mag... :P
Nun, "aneinandergeraten" is wohl ein wenig hart, zumindest von mir aus war das jetzt nicht ganz so ernst gemeint. Aber in der Tat war meine Aussage da wohl nicht so technisch korrekt (the best kind of correct), wie ich dachte, da muss ich dir nun Recht geben...
Antworten