5

I'm using Simple-Web-Server library for creating simple web service for translation of XML to JSON and vice versa. On its turn it uses several boost libraries as well boost::coroutine among them. For XML<->JSON conversion I'm using boost::property_tree library for intermediate representation. Here is the code:

#include <iostream>
#include <sstream>

#include <server_http.hpp>

#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>

using namespace std;
using namespace boost::property_tree;

using HttpServer = SimpleWeb::Server<SimpleWeb::HTTP>;

int main()
{
  HttpServer server(8080, 1);

  server.resource["^/json_to_xml$"]["POST"] = [](auto& response, auto request) {
    try
    {
      ptree pt;
      read_json(request->content, pt);
      ostringstream json, xml;
      write_json(json, pt);
      clog << "JSON request content:" << endl << json.str() << endl;
      write_xml(xml, pt, xml_writer_make_settings<ptree::key_type>(' ', 1u));
      clog << "XML response content:" << endl << xml.str() << endl;
      response << "HTTP/1.1 200 OK\r\nContent-Length: " << xml.str().length() << "\r\n\r\n" << xml.str();
    }
    catch(const exception& e)
    {
      cerr << "Error:" << endl << e.what() << endl;
      response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << strlen(e.what()) << "\r\n\r\n" << e.what();
    }
  };

  server.resource["^/xml_to_json$"]["POST"] = [](auto& response, auto request) {
    try
    {
      ptree pt;
      read_xml(request->content, pt, xml_parser::trim_whitespace | xml_parser::no_comments);
      ostringstream xml, json;
      write_xml(xml, pt, xml_writer_make_settings<ptree::key_type>(' ', 1u));
      clog << "XML request content:" << endl << xml.str() << endl;
      write_json(json, pt);
      clog << "JSON response content: " << endl << json.str() << endl;
      response << "HTTP/1.1 200 OK\r\nContent-Length: " << json.str().length() << "\r\n\r\n" << json.str();
    }
    catch(const exception& e)
    {
      cerr << "Error:" << endl << e.what() << endl;
      response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << strlen(e.what()) << "\r\n\r\n" << e.what();
    }
  };

  server.start();

  return 0;
}

JSON to XML conversion works fine but the opposite causes the program to crash. When I'm not using boost::property_tree's XML parser in the server's callback the program works fine. Here is the result of execution. Here is GDB backtrace. And finally here is Valgrind output.

Used version of the boost libraries is 1.58.0 but the same result is observed with the newest version 1.61.0. Version 1.4.2 of the Simple-Web-Server is used.

bobeff
  • 3,543
  • 3
  • 34
  • 62
  • That's a lot of code. It would appear as if the Simple-Web-Server isn't production ready code. I've looked at it for a while but there are so many moving parts it's hard to get a handle on things. – sehe Jun 05 '16 at 12:07
  • The web service no longer crashes with [version 2.0](https://github.com/eidheim/Simple-Web-Server/tree/v2.0) of *Simple-Web-Server* which doesn't uses *boost::coroutine* any more, but I wondering whether this is some kind of incompatibility between *boost::coroutine* and *boost::property_tree* because I used both in the past and I have similar strange crashes described in [this](http://stackoverflow.com/questions/31610415/what-causes-a-random-crash-in-boostcoroutine) question. Back then I didn't relate it to *boost::property_tree* XML parsing, but now I think that there can be some connection. – bobeff Jul 22 '16 at 08:35

1 Answers1

3

read_xml() might be overflowing your coroutine's stack; see here about a similar crash traced down to a 64K stack variable inside the rapidxml parser.

EDIT. To summarize the link... the gist of the matter is, the rapidxml parser buried within read_xml allocates 64K on the stack, which overflows the 8K default coroutine stack on Linux. You can try two things... either force that stack variable to be smaller, e.g.,

#define BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE 512
#include <boost/property_tree/xml_parser.hpp>

or allocate a larger stack when the coroutine is spawned (if it's possible to access that through Simple-Web-Server)

R. Li
  • 56
  • 3
  • Great answer! I'm waiting for this so long. We had a similar problem with production code in my previous company which is described [here](https://stackoverflow.com/questions/31610415/what-causes-a-random-crash-in-boostcoroutine) and back than we didn't recognize that the problem is in RapidXML. – bobeff Aug 22 '17 at 19:59