Reputation: 983
I'm trying to load a JSON document using rapidjson. After parsing, the assertion doc.IsObject() fails and I can't understand why. I am absolutely sure that the filename is correct and I tested jsonContent : OK as well.
Here is the loading code :
std::ifstream file(filename);
std::string jsonContent( (std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
rapidjson::Document doc;
doc.Parse < rapidjson::kParseStopWhenDoneFlag, rapidjson::UTF8<> >(jsonContent.c_str(), jsonContent.length());
assert(doc.IsObject());
Here is the loaded JSON :
{
"version": "170301",
"lang": "en"
}
Here is the output :
MyTest: /home/dev/Projects/myproject/src/loadJson.cpp:85: void loadFile(const std::string &): Assertion `doc.IsObject()' failed. unknown location(0): fatal error in "MyTest": signal: SIGABRT (application abort requested)
I executed this with gdb and got the following information (breakpoint right before assert):
(gdb) p doc
$1 = {<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >> = {static kDefaultArrayCapacity = 16, static kDefaultObjectCapacity = 16, data_ = {s = {
length = 2, hashcode = 2,
str = 0x30000006a5b48 <error: Cannot access memory at address 0x30000006a5b48>}, ss = {
str = "\002\000\000\000\002\000\000\000H[j\000\000"}, n = {i = {i = 2,
padding = "\002\000\000"}, u = {u = 2, padding2 = "\002\000\000"}, i64 = 8589934594,
u64 = 8589934594, d = 4.2439915829186759e-314}, o = {size = 2, capacity = 2,
members = 0x30000006a5b48}, a = {size = 2, capacity = 2, elements = 0x30000006a5b48}, f = {
payload = "\002\000\000\000\002\000\000\000H[j\000\000", flags = 3}}},
static kDefaultStackCapacity = 1024, allocator_ = 0x7fff00000000, ownAllocator_ = 0x691460,
stack_ = {allocator_ = 0x691460, ownAllocator_ = 0x0, stack_ = 0x0, stackTop_ = 0x0,
stackEnd_ = 0x0, initialCapacity_ = 0}, parseResult_ = {code_ = **rapidjson::kParseErrorNone,**
offset_ = 0}}
(gdb) p doc.GetType()
$2 = rapidjson::kObjectType
(gdb) p doc.IsObject()
$3 = false
(gdb) p jsonContent
$4 = "{\n\t\"version\": \"170301\",\n\t\"lang\": \"en\"\n}\n\n"
I tried all the variants listed here and I get the same assertion fail with all of them.
Upvotes: 1
Views: 2329
Reputation: 975
A good way to solve this issue is to copy the std::string into a statically allocated char (byte) array. Make sure to call parse with a statically allocated buffer, instead of dynamic. If you do the conversion making sure you follow JSON standard, rapidjson will work.
You basically want to store each character into a byte slot as: [0]: '{', [1]: '"', [2]:"v", [3]: "e" ... (hopefully you see the point). Makes sure you are not storing something like: [0]:'{', [1]:'\', [2]:""", [3]: "v" ... which will lead to another set of issue with the parser.
Basically, that's what Milo is getting to in his answer below. He used a static string, but that can be easily replaced with a static allocated buffer that can be filled up with JSON characters coming from std::string.
Upvotes: 0
Reputation: 1062
The problem is that your and Milo's code work on x86.
In fact it might be failing at runtime on ibm server (in my case).
Easiest guess that the key point is pointer size mismatch. Rapidjson assumes that the pointer size not longer than 64 bits which was not the case for some platforms and thus RAPIDJSON_ALIGN
corrupts data to be parsed in a way that it appears no to be a valid object at time of parsing.
The particular solution was to fallback to 64-bit sized pointer via compilation flags (TERASPACE
,LLP64
) and ensuring that modules actually went teraspace.
Also preprocessor command #pragma datamodel (LLP64)
might be used with proper setup verification.
Maybe these tricks would be helpful.
Upvotes: 0
Reputation: 5072
I cannot reproduce the problem by the following code:
#include <iostream>
#include "rapidjson/document.h"
int main() {
rapidjson::Document doc;
doc.Parse < rapidjson::kParseStopWhenDoneFlag, rapidjson::UTF8<> >("{\"version\": \"170301\",\"lang\": \"en\"}");
std::cout << doc.IsObject() << std::endl;
}
Upvotes: 1