RapidJSON beheben: Segmentation Faults beim Erstellen verschachtelter Dokumente
Problem:
Sie möchten eine RapidJSON-Anwendung erstellen, die ein JSON von Grund auf erstellt und Dokumente verwendet, die innerhalb anderer Dokumente verschachtelt sind, aber beim Ausführen sehen Sie eine Fehlermeldung wie
zsh: segmentation fault (core dumped) ./rapidjson-exampleLösung
Segmentation Faults (d.h. illegale Speicherzugriffe) können viele Ursachen haben, aber die häufigste ist, dass Sie lokale Allocatoren verwenden.
Um das Problem zu beheben, verwenden Sie einen Allocator für Ihre gesamte Anwendung.
MemoryPoolAllocator<> jsonAlloc; // Ich empfehle, dies statisch zu deklarieren
// ...
doc.AddMember("text", Value().SetString("Hello JSON!"), jsonAlloc);Beachten Sie, dass MemoryPoolAllocator niemals Speicher aus seinem Speicherpool freigibt.
Erklärung:
Viele RapidJSON-Beispiele empfehlen die Verwendung von Aufrufen wie
Document d;
doc.AddMember("text", ... , doc.GetAllocator());Aber der Ansatz, immer doc.GetAllocator() zu verwenden, funktioniert nur für sehr einfache Beispiele.
Der Grund für den Segfault scheint zu sein, dass sobald das Document den Gültigkeitsbereich verlässt, seine Allocator-Instanz freigegeben wird und der Speicher daher wiederverwendet wird. Ich habe das Problem jedoch bisher nicht weiter verfolgt.
Minimales Beispiel zur Reproduktion des Problems:
#include <iostream>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/ostreamwrapper.h>
using namespace rapidjson;
using namespace std;
Document generateInnerDoc() {
// Dokument generieren: {"text": "Hello JSON!"}
Document doc;
doc.SetObject(); // doc zu einem Objekt machen!
// Allokation über SetString() erzwingen
doc.AddMember("text", Value().SetString("Hello JSON!"), doc.GetAllocator());
return doc;
}
Document generateOuterDoc() {
// Dokument generieren: {"text": "Hello JSON!"}
Document doc;
doc.SetObject();
doc.AddMember("text", generateInnerDoc(), doc.GetAllocator());
return doc;
}
int main() {
// Auf stdout schreiben
OStreamWrapper out(cout);
// Dokument schreiben...
Writer<OStreamWrapper> writer(out);
generateOuterDoc().Accept(writer);
}Korrigiertes Beispiel:
#include <iostream>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/ostreamwrapper.h>
using namespace rapidjson;
using namespace std;
MemoryPoolAllocator<> jsonAlloc;
Document generateInnerDoc() {
// Dokument generieren: {"text": "Hello JSON!"}
Document doc;
doc.SetObject(); // doc zu einem Objekt machen!
// Allokation über SetString() erzwingen
doc.AddMember("text", Value().SetString("Hello JSON!"), jsonAlloc);
return doc;
}
Document generateOuterDoc() {
// Dokument generieren: {"text": "Hello JSON!"}
Document doc;
doc.SetObject(); // doc zu einem Objekt machen!
// Allokation über SetString() erzwingen
doc.AddMember("text", generateInnerDoc(), jsonAlloc);
return doc;
}
int main() {
// Auf stdout schreiben
OStreamWrapper out(cout);
// Dokument schreiben...
Writer<OStreamWrapper> writer(out);
generateOuterDoc().Accept(writer);
}