Huge Zahlenklasse mit RSA Absturz bei deconstructor


  • Mod

    Der Trick an Vector (oder eigenen Ressourcenklassen) ist ja gerade, dass auch diese für die Anwendungsklassen die Rule of 0 ermöglichen 🙂



  • @SeppJ sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Der Trick an Vector (oder eigenen Ressourcenklassen) ist ja gerade, dass auch diese für die Anwendungsklassen die Rule of 0 ermöglichen 🙂

    Ja stimmt, so hab ich das nicht gesehen. Mein Bild davon war eher, dass es immer noch beachtet werden muss, aber es eben "jemand anderes" bereits gemacht hat... für die std::vector verwendende Klasse ist das natürlich dennoch Rule of Zero 😉



  • Habe jetzt Speicher Zuordnung in eine extra klasse gepackt:

        template<>
        class array<unsigned char> {
        public:
            array() {
                _buf = nullptr;
                _size = 0;
                _length = 0;
            };
    
            array(array const& t) {
                _buf = nullptr;
                _size = t.size();
                _length = t.length();
                write(t.c_str(), t.size());
            };
    
            virtual ~array() {
                delete[] _buf;
            }
    
            array operator=(const unsigned char t) {
                clear();
                _buf = new unsigned char[1];
                _buf[0] = t;
                _size = 1;
                _length = 1;
                return *this;
            };
    
            void write(const unsigned char* t, unsigned long size) {
                if ((_size-_length) < size) {
                    resize((_length+size));
                }
                if(_length>0)
                    memcpy(_buf+(_length-1),t,size);
                else
                    memcpy(_buf,t, size);
                _length += size;
            }
    
            array operator=(array t) {
                clear();
                write(t.c_str(), t.size());
                _length = t.length();
                _size = t.size();
                return *this;
            }
    
            unsigned char& operator[](int pos) {
                return _buf[pos];
            };
    
            void resize(size_t size) {
                if (_length > size) {
                   return;
                }
                unsigned char* tmp = _buf;
                _buf = new unsigned char[size];
                memcpy(_buf,tmp,_length);
                _size = size;
                delete[] tmp;
            }
    
            size_t size() const {
                return _size;
            };
    
            size_t length() const {
                return _length;
            }
    
            void push_back(char t) {
                if (_size-_length < 1) {
                    resize(_length + 1);
                }
                _buf[_length] = t;
                ++_length;
            };
    
            void clear() {
                delete[] _buf;
                _size = 0;
                _length = 0;
                _buf = nullptr;
            };
    
            constexpr const unsigned char* c_str() const noexcept {
                return _buf;
            };
    
            size_t length() {
                return _size;
            };
    
            bool empty() {
                if (!_buf)
                    return true;
                return false;
            }
    
        private:
            unsigned char* _buf;
            size_t         _size;
            size_t         _length;
        };
    

    leider bekomme ich bei resize folgenden Fehler:

    libc.so.6!__memmove_avx_unaligned_erms() Line 254 C++



  • fehler gefunden:

            array(array const& t) {
                _buf = nullptr;
                _size = t.size();
                _length = t.length();
                write(t.c_str(), t.size());
            };
    

    zu

            array(array const& t) {
                _buf = new unsigned char[t.size()];
                memcpy(_buf,t._buf,t.length());
                _size = t.size();
                _length = t.length();
            };
    


  • @Tuxist1
    Und warum nutzt du nicht std::array oder std::vector?



  • @Tuxist1
    Ich habe noch ein paar Fragen/Anmerkungen bezüglich deiner array Implementierung:

    • Ist dein array eigentlich nicht ein std::basic_string? Wenn ja, warum spezialisierst du dann das Template?
    • Wo ist dein Move Konstruktor und deine Move Zuweisung?
    • Warum allokierst du ständig einen neuen Puffer, wenn du ein Zeichen hinzufügst? Nehmen wir mal an, du möchtest ein Bild der Größe 1920x1280 einlesen. Dann würde deine Klasse 1920x1280 = 2457600 Allokationen durchführen. Ein std::vector führt unter VS 2019 in diesem Fall aber nur um die 40 Allokationen aus. Warum? Weil gilt "Neue Containergröße = Alte Containergröße * 1.5"
    • Wie sieht es mit deiner Exception Safety aus? (Stichwort Copy-Swap Idiom)
    • Solltest du da nicht auch noch eine Small String Optimization implementieren?
    • Wird eine leere Instanz gelöscht, so rufst du die Funktion delete mit einem nullptr auf.


  • Es gibt einen zweiten branch wo ich noch die libc mit implementiere kann deshalb kein std:: einbinden kann da std:: wiederum von der libc abhängig ist.

    Das hier ist nur mein testbranch.



  • @Tuxist1 sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Es gibt einen zweiten branch wo ich noch die libc mit implementiere kann deshalb kein std:: einbinden kann da std:: wiederum von der libc abhängig ist.

    Was verwendet denn der operator new bei dir unter der Haube? Üblicherweise baut der auf malloc auf und das ist für gewöhnlich Teil der libc. Alles natürlich nicht obligatorisch, letztendlich kann man sich das alles beliebig zusammenstöpseln.

    Wenn du also irgendwo eine malloc-Implementierung hast, dann ist das meiner Einschätzung nach alles was ein std::vector oder ein std::basic_string brauchen. Ich weiss allerdings nicht, wie gut sich diese Klassen aus deiner C++-Standardbibliothek isolieren lassen, wenn malloc/free alles ist, was man hat und der Rest der libc fehlt. Die libstdc++ hab ich jedenfalls bisher immer mit einer vorhandenen libc gebaut. Vielleicht lohnt es sich das mal zu recherchieren. Eventuell auch mal libc++ anschauen. Die ist nicht so alt und könnte eventuell solche etwas unorthodoxeren Setups besser unterstützen.



  • Die Frage ist auch um was für eine (Hardware) Platform es sich hier handelt, und was der Grund ist, das auf eine libc (um welchen denn überhaupt?) verzichtet werden muss.



  • @Finnegan sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Wenn du also irgendwo eine malloc-Implementierung hast, dann ist das meiner Einschätzung nach alles was ein std::vector oder ein std::basic_string brauchen.

    Nein, da kommt einiges an Abhängigkeiten zusammen. Das fängt damit an, dass die Container nicht malloc nutzen sondern std::allocator<T>, und dann kommen da so Abhängigkeiten wie die Traits-, Exception-, … -Header dazu.



  • Noch ein Tipp von mir: Arbeite dich in Unittests ein und teste deine Module ( z.B. dein Array ) einzeln ab. Unittests sind ein wirksames mittel gegen solche Fehler wie bei deinem Resize.
    Und selbst wenn du kein Test-Framework aus irgendwelchen Gründen verwenden kannst, kannst du trotzdem Unittests programmieren, denn letztendlich prüfst du nur Rückgabewerte oder Stati von irgendwelchen Variablen und dazu braucht es nicht zwingend ein Framework wie gtest oder anderes.



  • @john-0 sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    @Finnegan sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Wenn du also irgendwo eine malloc-Implementierung hast, dann ist das meiner Einschätzung nach alles was ein std::vector oder ein std::basic_string brauchen.

    Nein, da kommt einiges an Abhängigkeiten zusammen. Das fängt damit an, dass die Container nicht malloc nutzen sondern std::allocator<T>, und dann kommen da so Abhängigkeiten wie die Traits-, Exception-, … -Header dazu.

    Ich meine damit schon externe Abhängigkeiten. Der Default-Allocator std::allocator<T> dürfte mit dem malloc der libc implementiert sein und bei den anderen genannten Headern sehe ich nicht, was die aus der libc brauchen sollten. Exception Handling könnte eventuell Unterstützung einer (externen) Compiler-Runtime benötigen, die auch wiederum Abhängigkeiten haben kann. So genau weiss ich das nicht. Wie ich schon sagte, es is möglich, dass sich das je nach Implementierung der C++-Standardbibliothek alles nicht so leicht voneinander trennen lässt, aber ich sehe nicht wie ein std::vector inklusive aller Abhängigkeiten grundsätzlich mehr als die malloc-Implementierung aus der libc benötigen sollte.



  • @Finnegan sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Der Default-Allocator std::allocator<T> dürfte mit dem malloc der libc implementiert sein …

    Ja, es ist eine der Möglichkeiten, aber es gab/gibt hinreichend viele Compiler die unter UNIX/Linux (keine Ahnung wie die API auf anderen Plattformen aussieht) direkt brk/sbrk nutzen. Und die ganzen Header sollte man auch nicht unterschätzen, weil man sie ggf. erst einmal implementieren muss.



  • @john-0 sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    @Finnegan sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Der Default-Allocator std::allocator<T> dürfte mit dem malloc der libc implementiert sein …

    Ja, es ist eine der Möglichkeiten, aber es gab/gibt hinreichend viele Compiler die unter UNIX/Linux (keine Ahnung wie die API auf anderen Plattformen aussieht) direkt brk/sbrk nutzen. Und die ganzen Header sollte man auch nicht unterschätzen, weil man sie ggf. erst einmal implementieren muss.

    brk/sbrk/mmap sind schon ziemlich low-level, erstere mehr wie ne Stack-Allokation und letzteres auf Speicherseiten-Ebene. Da bräuchte es auf jeden Fall noch ne generische Speicherverwaltung obendrauf die etwas platzeffizienter für beliebige angeforderte Größen ist und den Speicher auch sinnvoll freigeben und wiederverwenden kann. Eben sowas wie malloc. Die genannten Compiler müssten dann sowas selbst mitbringen.

    Ich wollte es aber nicht zu sehr abschweifen lassen. Eigentlich war ich ja hauptsächlich neugierig, wo bei @Tuxist1 der operator new herkommt ohne libc. Kann man natürlich auch separat einbauen.



  • @Tuxist1 sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Es gibt einen zweiten branch wo ich noch die libc mit implementiere kann deshalb kein std:: einbinden kann da std:: wiederum von der libc abhängig ist.

    Sorry das ich da mal nachhake.

    Aber ich verstehe nicht warum man libc bzw. STL nicht nutzen möchte.

    In der STL steckt eine Menge Hirnschmalz und lässt sich nicht so einfach nachprogrammieren. Deine array Implementierung mit c_str() Funktion z.B. sieht unter Visual Studio folgendermaßen aus:

    https://github.com/microsoft/STL/blob/main/stl/inc/xstring

    Und wo ich gerade in deinem Repo eine Datei namens atomic.cpp sehe, möchte ich dir auch die Visual Stdio Variante zeigen:

    https://github.com/microsoft/STL/blob/main/stl/inc/atomic

    8000 LOC, Holla die Waldfee



  • Und dass keine libc verwendet wird ist aktuell nicht korrekt.

    z.b. werden folgende header in verschiedenen cpp dateien inkludiert:

    Wobei eventuell der Plan ist, diese durch eine eigene Implementierung zu ersetzen?

    Wenn es nicht gerade aus reiner spielerei/wissbegierde ist, sollte man das tunlichst vermeiden so was selbst zu implementieren.



  • in dem main branch wird libc mit implementiert:

    https://tuxist.de/git/jan.koester/systempp/-/tree/main

    habe einen zweiten branch der mit standart libc gebaut wird:

    https://tuxist.de/git/jan.koester/systempp/-/tree/without-libc

    wollte erstmal in den zweiten tree https einbauen damit das backend von meinem Blog
    "http://tuxist.de" wieder funktioniert hat mit den cookie richtlinien zu tun.

    Aber jetzt mal zu systempp soll die basis von fenriros bilden, im moment bin ich unzufrieden über den wildwuchs von unix/linux konfiguartions Dateien jeder und alles macht da was er will führt dazu das es unnötig viel Arbeit konfigurations Oberflächen dafür zu schreiben. Das zweite Problem was ich sehe ist das man auf tiefere ebene zum teil sehr schwerig zu verstehende api hat und meist nur auf c ebene. Ich versuche da Abhilfe zu schaffen da ich als Rentner jetzt zeit dafür habe.

    Unterschiede Fenriros zu anderen Posix Systemen:
    -confdb mit conffs eine art registry
    -sid statt fortlaufender uid's nt kompatible
    -vollständige C++ ABI
    -bsd lizens
    -keine gnu abhängikeiten

    Nach dem https implementiert werde ich mich wieder meinem elfparser widmen damit ich endlich in System chrooten kann und danach stdio implementieren danach noch paar kleine posix geschichten damit hoffentlich llvm unter der chroot kompeliert der basis Compiler für das System. Danach Feinit damit ich ein init system habe und CMake support für Linux Kernel und Python.



  • @Tuxist1 sagte in Huge Zahlenklasse mit RSA Absturz bei deconstructor:

    Ich versuche da Abhilfe zu schaffen da ich als Rentner jetzt zeit dafür habe.

    Wenn ich so deinen letzten Beitrag lese, habe ich das Gefühl dass du dich übernimmst. Die Libc nachzuprogrammieren ist keine kleine Sache, ebenso Verschlüsselung und erst Recht nicht eine Grundlage eines Betriebssystems.

    Aus meiner Sicht wäre das Aufgabe eines kleinen Entwicklungsteams für die nächsten X Jahre.



  • @Quiche-Lorraine da hast du recht bin ich schon 4 Jahre bei spalte immer wieder Sachen ab die ich auch so gebrauchen kann, das hält meine Motivation am laufen. Das schöne ist mal lernt unheimlich viel.


Anmelden zum Antworten