0

I have a class representing an object in 3-space, and a to_json method which outputs a const char* to convert the object into a JSON for writing back to a document based database. However, the to_json method is outputting unknown characters rather than a JSON Message

const char* Obj3::to_json() const
{
    logging->info("Obj3:To JSON Called");
    //Initialize the string buffer and writer
    StringBuffer s;
    Writer<StringBuffer> writer(s);

    //Start writing the object
    //Syntax taken directly from
    //simplewriter.cpp in rapidjson examples

    writer.StartObject();

    writer.Key("key");
    std::string key = get_key();
    writer.String( key.c_str(), (SizeType)key.length() );

    writer.Key("owner");
        std::string owner_dev = get_owner();
        writer.String( owner_dev.c_str(), (SizeType)owner_dev.length() );

    writer.Key("name");
    std::string name = get_name();
    writer.String( name.c_str(), (SizeType)name.length() );

    writer.Key("type");
    std::string type = get_type();
    writer.String( type.c_str(), (SizeType)type.length() );

    writer.Key("subtype");
    std::string subtype = get_subtype();
    writer.String( subtype.c_str(), (SizeType)subtype.length() );

    int i;
    int j;

    writer.Key("location");
    writer.StartArray();
    for (i=0; i<3; i++) {
        writer.Double( static_cast<double>(get_loc(i)) );
    }
    writer.EndArray();

    writer.Key("transform");
    writer.StartArray();

        for (i=0; i<4; i++) {
        writer.StartArray();
        for (j=0; j<4; j++) {
                writer.Double( static_cast<double>(transform_matrix(i, j) ));
        }
        writer.EndArray();
        }

        writer.EndArray();

    writer.Key("scenes");
    writer.StartArray();
        for (i=0; i<num_scenes(); i++) {
        std::string sc = get_scene(i);
                writer.String( sc.c_str(), (SizeType)sc.length() );
        }
        writer.EndArray();

    writer.Key("locked");
    writer.Bool(is_locked);

    writer.EndObject();

    //The Stringbuffer now contains a json message
    //of the object
    if (writer.IsComplete()) {
        logging->debug("Valid JSON Encountered");
        try {
            return s.GetString();
        }
        catch (std::exception& e) {
            logging->error("Exception Encountered parsing JSON");
            logging->error(e.what());
        }
    }
    else {
        return "";
    }

}

The logs show the below output:

2016-04-30 13:15:54,151 [INFO] Obj3:To JSON Called
2016-04-30 13:15:54,151 [DEBUG] Valid JSON Encountered
��

I've closed all of the arrays and the root object, and am checking for completeness per the API, however the output is not readable via std::cout or log4cpp.

--Edit--

Per the below response, I updated the return type to std::string and the return statement to the below:

//The Stringbuffer now contains a json message
//of the object
if (writer.IsComplete()) {
    logging->debug("Valid JSON Encountered");
    try {
        const char* ret_val = s.GetString();
        std::string ret_string (ret_val);
        return ret_string;
    }
    catch (std::exception& e) {
        logging->error("Exception Encountered parsing JSON");
        logging->error(e.what());
    }
}
else {
    return "";
}

Which results in a segmentation fault.

The method is being called in the test as below:

std::cout << obj.to_json() << std::endl;

Alex Barry
  • 415
  • 1
  • 9
  • 21

1 Answers1

1

The const char * return value is pointing to the s value, which is on the stack. It's getting freed before you use it.

Instead, consider making the function return a string type (e.g. std::string) which retains its storage.

Todd Christensen
  • 1,297
  • 8
  • 11
  • See updates above, I tried replacing the return type and am receiving a segmentation fault. – Alex Barry Apr 30 '16 at 17:57
  • Where is it segfaulting? Is it actually segfaulting on the return? You don't really need a temporary, you can just `return s.GetString()` with a return type of `std::string`. Also, `Writer::String()` can take a std::string directly too. – Todd Christensen Apr 30 '16 at 18:08
  • One way to debug might be returning "" in both cases. That way you can validate that the changed return type isn't somehow related to the segfault. – Todd Christensen Apr 30 '16 at 18:09
  • Yes, the segfault is actually coming inside of the Writer::String() calls and not the return. Why would this generate a segfault now and not before? – Alex Barry Apr 30 '16 at 18:21
  • Might just be the way the stack was organized before, you got lucky. – Todd Christensen Apr 30 '16 at 19:00
  • Thank you, I fixed the segfault and it my tests are passing, I've marked your answer as correct. – Alex Barry Apr 30 '16 at 19:30