Problem mit popen / pclose unter Linux
-
Hallo,
ich hoffe, ich bin im richtigen Bereich mit meiner Frage. Ich habe folgende Methode geschrieben:
signed Executable::execute(std::vector<std::string>& result) const { constexpr uint64_t MessageLength = 128; const std::string pathInclParameters(getPath().string() + (parameters.empty() ? StdLibs_Null : (StdLibs_Space + parameters))); #ifdef UNIX std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(pathInclParameters.c_str(), "r"), pclose); #endif #ifdef WINDOWS std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(pathInclParameters.c_str(), "r"), _pclose); #endif if (pipe) { try { while (!feof(pipe.get())) { std::array<char, MessageLength> buffer = { 0 }; if (fgets(buffer.data(), MessageLength, pipe.get()) != nullptr) { std::string localString; for (uint64_t index = 0; index < MessageLength; index++) { if ((buffer.at(index) == StdLibs_Character_NewLine) || (buffer.at(index) == StdLibs_Character_Null)) { break; } localString += buffer.at(index); } result.push_back(localString); } } #ifdef UNIX return pclose(pipe.get()); #endif #ifdef WINDOWS return _pclose(pipe.get()); #endif } catch (const std::exception& exception) { throw Exception(SomethingGoesWrong, StdLibs_Exception_StackTraceEntry, exception); } } throw Exception(PipeCouldNotBeOpened, StdLibs_Exception_StackTraceEntry); }
Ziel dieser Methode ist es, ein beliebiges Programm aufzurufen und deren Ausgabe in einen Vektor zu schreiben, um ihn im späteren Programmverlauf auswerten zu können.
Unter Windows habe ich keine Probleme, keine Speicherlöcher, alles bestens. Hier baue ich mit Visual Studio 2019 und dem 17er C++ Standard.
Unter Linux (Ubuntu Desktop, v20) bekomme ich den folgenden Fehler auf der Kommandozeile beim Ausführen:
free(): double free detected in tcache 2
Aborted (core dumped)Nach einigen Debugversuchen bin ich soweit gekommen, dass der Fehler bei dem Return-Statement auftritt. Ich bin nun leider etwas ratlos. Unter Linux baue ich mit dem G++ (v9.3.0) und ebenso dem 17er C++ Standard.
Kann jemand helfen?
lg Torsten
-
Auf den ersten Blick (vom Handy) fällt mir das doppelte pclose auf. Du schließt die Datei im return manuell und durch den unique_ptr zusätzlich automatisch nochmal. Durch return pclose(pointer.release() statt .get()) würdest du nur 1x schließen.
Edit: ist denn die while-Loop mit dem eof-Test obrn richtig? Das sieht normalerweise immer falsch aus.
-
Danke @wob
Ich weiß leider nicht mehr woher ich die Variante habe, würde mich interessieren, ob ich es 1:1übernommen habe oder selbst diesen dummer Fehler eingebaut habe
Was meinst du mit "falscher while-Schleife"?
lg Torsten
-
Alle Schleifen, die mit
while (!eof(filehandle))
beginnen, sind hochverdächtig. Das ist ein Pattern, das so nicht funktioniert (außer in Pascal).Das eof wird erst erkannt, NACHDEM das Ende gelesen wurde. Daher ist eine "normale" Schleife beim Einlesen in der Art
while (einlesen erfolgreich) { verarbeite eigelesene Daten }
. Wie ich sehe, hast du das mit einem zusätzlichenif
um das fgets gelöst - aber dieses "if" kannst du auch direkt im "while" nutzen. Siehe das Beispiel hier: https://en.cppreference.com/w/c/io/fgetsWenn du dann aus dem while raus bist, kannst du mit dem eof feststellen, ob du am Ende der Datei bist - und wenn nicht, mit ferror einen Fehler ausgeben.