Konvertierung von 'size_t' nach 'int', Datenverlust möglich (Split aus: Extremnekromantie)



  • Hi,

    Du arbeitest wohl mit einem Atart ST (Amiga?) oder einem 64-Bit System. Wie auch immer, jedenfalls ist offensichtlich sizeof( int ) < sizeof( std::size_t ).

    1. Problem:

    send erwartet als 3. Parameter einen int. string::length liefert aber ein size_t.

    Lösung: prüfe ob String zu lange ist. Wenn ja, schicke mehrere Chunks in der passenden Länge, oder werfe eine Exception und caste den dritten Parameter beim Aufruf von send.

    2. Problem:
    Ändere den Typ von p_iParaLen in std::size_t

    mfg Martin



  • mgaeckler schrieb:

    jedenfalls ist offensichtlich sizeof( int ) < sizeof( std::size_t ).

    Mmh?
    Du meinst std::numeric_limits<>::max()?



  • Jockelx schrieb:

    mgaeckler schrieb:

    jedenfalls ist offensichtlich sizeof( int ) < sizeof( std::size_t ).

    Mmh?
    Du meinst std::numeric_limits<>::max()?

    Das ist dann die Folge meiner obigen Aussage:

    wenn sizeof( x1 ) < sizeof( x2 ) dann std::numeric_limits<x1>::max() < std::numeric_limits<x2>::max().

    Jedenfalls gilt das für alle Systeme, die ich kenne.

    VG



  • Echt?
    Ich weiss es nicht, hätte jetzt aber intuitiv gedacht, dass idR sizeof(int) = sizeof(size_t) ist, also size_t einfach ein unsigned int ist.



  • Jockelx schrieb:

    Echt?
    Ich weiss es nicht, hätte jetzt aber intuitiv gedacht, dass idR sizeof(int) = sizeof(size_t) ist, also size_t einfach ein unsigned int ist.

    Auf 32 Bit Systemen vielleicht. Auf allen mir bekannten aktuellen Systemen ist size_t 8 Byte groß und int nur 4.



  • Jockelx schrieb:

    Ich weiss es nicht, hätte jetzt aber intuitiv gedacht, dass idR ...

    Das ist das Problem.

    Immerhin gibst du zu, dass du es nicht weißt.

    Du kannst bei C/C++ nicht von dem Verhalten auf deinem System auf alle anderen Systeme schließen.

    64-Bit Systeme gibt es schon länger (die Symptome sind aber nicht darauf beschränkt)

    mgaeckler schrieb:

    Du arbeitest wohl mit einem Atart ST (Amiga?) ...

    Gerade das waren schon echte 32-Bit Systeme, im Gegensatz zum DOS, das noch 16-Bit war, aber durchaus 32-Bit Adressen (Segment:Offset) hatte



  • DirkB schrieb:

    Das ist das Problem.

    Jau, riiiiesen Problem!!! Atomkraftwerke werden explodieren!
    Ich wusste nicht, das size_t idR nicht nur stets einen grösseren max-Wert hat als int, sondern einen noch grösseren!


  • Mod

    Jockelx schrieb:

    DirkB schrieb:

    Das ist das Problem.

    Jau, riiiiesen Problem!!! Atomkraftwerke werden explodieren!

    Ähh, die Ariane 5 ist wegen so etwas explodiert.



  • DirkB schrieb:

    mgaeckler schrieb:

    Du arbeitest wohl mit einem Atart ST (Amiga?) ...

    Gerade das waren schon echte 32-Bit Systeme [...]

    bis auf den 16-Bit Datenbus der 68000 CPU



  • SeppJ schrieb:

    Ähh, die Ariane 5 ist wegen so etwas explodiert.

    Ähh, nein, ist sie nicht.
    Es geht hier ja nicht um overflows.
    (Bzw. wo genau kann das Problem entstehen, wenn ich weiss, dass mein Typ (size_t) immer einen grösseren max-wert hat, als ein anderer, aber der max-wert noch grösserer ist als angenommen.)

    Im Grunde auch wurscht diese Diskussion, ich fand nur dieses grosskotizge "das ist dein Problem, aber wenigstens gibtst du es zu, wie dumm du bist" so armselig.


  • Mod

    Jockelx schrieb:

    SeppJ schrieb:

    Ähh, die Ariane 5 ist wegen so etwas explodiert.

    Ähh, nein, ist sie nicht.
    Es geht hier ja nicht um overflows.

    Und wenn du Daten verlierst, weil du nicht auf die Möglichkeit eines Overflows achtest, dann ist das für dich kein Problem ähnlicher Art als wenn du Daten verlierst, weil du sie in einen zu kleinen Typ konvertieren möchtest? Willst du dich an der semantischen Feinheit aufziehen, dass noch nie ein Atomkraftwerk wegen exakt diesem Problem explodiert ist, wenn es unzählige Beispiele gibt, bei denen ähnlich wichtige Dinge wegen ähnlicher Probleme explodiert sind?

    Die Erkenntnis die du mitnehmen solltest ist doch, dass diese Probleme, die dir als kleinkarierte Paragraphenreiterei erscheinen mögen, ganz reale Auswirkungen haben können, die sehr sehr relevant sind. Deine Anwendungen werden nicht korrekt funktionieren, wenn du auf so etwas nicht acht gibst, und wenn du etwas wichtiges programmierst, dann wird demzufolge etwas wichtiges nicht funktionieren. Und dann stürzt eine Rakete für 100 Millionen Euro ab, weil jemand es nicht für wichtig genug befunden hat, sauber zu programmieren.

    Was ist, wenn die Nachricht, die der TE hier verschicken möchte, etwas wichtiges steuert? Ist es dann immer noch egal, dass das Programm wer weiß was tut, wenn die Nachricht zu lang ist? Schade, dass du diese wichtige Lektion lieber als persönlichen Angriff auf dich abtust, anstatt daraus zu lernen.



  • Hm, aber das die Typen unterschiedliche Wertebereiche haben und man darauf achten muss, hatte Jockelx doch geschrieben. Die Einzige Unwissenheit war doch, dass es sein kann, dass sizeof(size_t) > sizeof(unsigned int). Daraus mitnehmen sollte man, dass man size_t auch nicht nach unsigend int konvertieren sollte (zumindest nicht ohne extra überprüfungen). Aber für das Problem des TE, der nach int konvertieren will, sollte es wenig unterschied machen, ob sein Ausganstyp size_t oder unsigned int ist. Ob der abzubildende Wert da rein passt, muss er so oder so überprüfen.



  • DirkB schrieb:

    mgaeckler schrieb:

    Du arbeitest wohl mit einem Atart ST (Amiga?) ...

    Gerade das waren schon echte 32-Bit Systeme, im Gegensatz zum DOS, das noch 16-Bit war, aber durchaus 32-Bit Adressen (Segment:Offset) hatte

    Der ST hatte einen 16-Bit Datenbus. Daher wurde dort das int ebenfalls mit 16 Bit definiert. Intels 32-Bit Systeme hatten mit Ausnahme vom 386SX einen 32-Bit Datenbus. Daher wurden dort ints mit 32 Bit definiert.

    VG



  • SeppJ schrieb:

    Und wenn du Daten verlierst

    Ich verliere keine Daten, wenn ich einen kleineren Typen in einen grösseren konvertiere, insbesondere dann nicht, wenn der grössere Typ noch grösser ist, als ich dachte.

    Schlangenmensch schrieb:

    Hm, aber das die Typen unterschiedliche Wertebereiche haben und man darauf achten muss, hatte Jockelx doch geschrieben.

    Danke fürs lesen.


  • Mod

    Jockelx schrieb:

    SeppJ schrieb:

    Und wenn du Daten verlierst

    Ich verliere keine Daten, wenn ich einen kleineren Typen in einen grösseren konvertiere, insbesondere dann nicht, wenn der grössere Typ noch grösser ist, als ich dachte.

    size_t darf genausogut auch kleiner als int sein. Wichtig ist jedenfalls, dass der Compiler hier nicht grundlos warnt und man dies schon ernst nehmen sollte.



  • SeppJ schrieb:

    size_t darf genausogut auch kleiner als int sein.

    Äh, okay...also sind alle vorherigen Aussagen noch 'falscher' als meine!?
    Hättest du dann aber auch gerne schon vorher mal erwähnen können, hätte uns einiges erspart.

    SeppJ schrieb:

    Wichtig ist jedenfalls, dass der Compiler hier nicht grundlos warnt und man dies schon ernst nehmen sollte.

    Hab ich nie bestritten.



  • SeppJ schrieb:

    size_t darf genausogut auch kleiner als int sein.

    Das würde ich jetzt anzweifeln.

    Aus der Dokumentation:

    size_t can store the maximum size of a theoretically possible object of any type (including array).

    Wenn also sowas erlaubt ist:

    std::array<unsigned int, std::numeric_limits<unsigned int>::max()> testArray;
    

    muss size_t mindestens so groß sein wie int.

    Edit: Mein Beispiel muss aber nicht erlaubt sein, also alles rückgängig!

    Edit 2: Was es aber bedeutet ist, dass es keine Objekte geben kann, die größer sind als durch size_t darstellbar. Also ist man, wenn man irgendwelche Objekte umkopiert oder versendet, mit size_t immer auf der sicheren Seite...


  • Mod

    Jockelx schrieb:

    SeppJ schrieb:

    size_t darf genausogut auch kleiner als int sein.

    Äh, okay...also sind alle vorherigen Aussagen noch 'falscher' als meine!?

    Ich sehe zwei Hauptaussagen:
    1. sizeof(size_t) und sizeof(int) haben absolut nichts miteinander zu tun. Offensichtlich ist diese Aussage objektiv richtig, denn hier ist sizeof(int) < sizeof(size_t) und es gibt unzählige weitere Beispiele (eigentlich alles außer den üblichen 32 Bit Systemen der späten 90er und frühen 2000er) bei denen sizeof(size_t) != sizeof(int). Und natürlich auch viele Beispiele bei denen sizeof(size_t) == sizeof(int) (nämlich eben die erwähnten 32 Bit Systeme), denn dass sie nichts miteinander zu tun haben, schließt nicht aus, dass sie gleich sein dürfen.
    2. Es ist wichtig, solche Feinheiten im Sprachstandard ernst zu nehmen. Ob diese Aussage richtig oder falsch ist, ist eher subjektiv. Wegen genau diesem Problem ist wahrscheinlich noch niemand gestorben, aber wegen verwandter Fehler sind durchaus schon reale Werte in großem Stil vernichtet worden. Wenn dir Overflows nicht passen, weil du sie eher als echten Programmierfehler ansiehst, dann nimm stattdessen Beispiele, bei denen z.B. der Linuxkernel ein Sicherheitsloch hatte, weil der Compiler ein undefiniertes Codestück wegoptimiert hatte (was er darf, da undefiniert).



  • SeppJ schrieb:

    size_t darf genausogut auch kleiner als int sein. Wichtig ist jedenfalls, dass der Compiler hier nicht grundlos warnt und man dies schon ernst nehmen sollte.

    Aktuelles Beispiel, das nicht aus grauer Vorzeit stammt: Arduino (Nano zumindest): sizeof(size_t) = 2 und sizeof(int) = 4
    Es ist schon richtig, dass man für portablen Code keine wie auch immer geartete Relation zwischen beiden annehmen sollte.


Anmelden zum Antworten