RapidJSON beheben: Segmentation Faults beim Erstellen verschachtelter Dokumente

English Deutsch

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

output.txt
zsh: segmentation fault (core dumped)  ./rapidjson-example

Lö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.

allocator_example.cpp
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

rapidjson_local_allocator_example.cpp
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:

rapidjson_repro.cpp
#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:

rapidjson_fixed.cpp
#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);
}

Check out similar posts by category: C/C++