Re: [cpp-netlib] Invalid characters

85 views
Skip to first unread message

Dean Michael Berris

unread,
Apr 15, 2012, 8:53:18 PM4/15/12
to cpp-n...@googlegroups.com
On Sun, Apr 15, 2012 at 4:04 AM, Mark <ma74...@gmail.com> wrote:
>
> Assume the command line program below is executing.
>
> I'll launch firefox (or explorer), then type in http:127.0.0.1:8080.
> If I depress enter repeatedly, I receive
>
> ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ
>
> Occasionally, I receive the correct response.  For example: "Hello
> World! Mark 10" within the browser window.
>
> Any ideas on what I receive the invalid (ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ)
> characters?
>

These are the offending lines:

>        std::vector<boost::asio::const_buffer> iovec;
>        iovec.push_back(boost::asio::const_buffer( msg.c_str(), sz ) );
>        connection->write(iovec, boost::bind(&async_hello_world::error, this,
> _1));
>

The problem here is that iovec doesn't own the memory pointed to by
the const_buffer instances. This means you are probably accessing
memory that's uninitialized or that's been re-used or something else.
What happens here is that when you do 'connection->write(...)' it
returns immediately and therefore the string owning the message is
destroyed. By the time the data is read/written to the socket it's
been deleted and therefore you're invoking undefined behavior.

The pattern here should be that you create a per-request object that
knows how to handle the result of connection->write(...) and handles
all the necessary state associated with the transfer. This includes
creating somethings that's reference-counted (in a shared_ptr<...>)
and passing the callback using bind and this reference-counted object.

The alternative to this approach is to just do `connection->write(msg,
boost::bind(&async_hello_world::error, this, _1));` and not have to
worry about the management of the data buffers.

Cheers

--
Dean Michael Berris
Technical Solutions Engineer
Google

Mark

unread,
Apr 22, 2012, 4:48:06 PM4/22/12
to The C++ Network Library


On Apr 15, 8:53 pm, Dean Michael Berris <dber...@google.com> wrote:

>
> These are the offending lines:
>
> >        std::vector<boost::asio::const_buffer> iovec;
> >        iovec.push_back(boost::asio::const_buffer( msg.c_str(), sz ) );
> >        connection->write(iovec, boost::bind(&async_hello_world::error, this,
> > _1));
>
> The problem here is that iovec doesn't own the memory pointed to by
> the const_buffer instances. This means you are probably accessing
> memory that's uninitialized or that's been re-used or something else.
> What happens here is that when you do 'connection->write(...)' it
> returns immediately and therefore the string owning the message is
> destroyed. By the time the data is read/written to the socket it's
> been deleted and therefore you're invoking undefined behavior.

Dean, two things:

a)

How is that different than the example which reflects:

std::vector<boost::asio::const_buffer> iovec;
iovec.push_back(boost::asio::const_buffer(hello_world, 13));
connection->write(iovec, boost::bind(&async_hello_world::error,
this, _1));

b)

Upon receipt of a client request and prior to invocation of the
functor ( asynch_hello_word example ) the destructor is invoked 15
times. The functor will run (ie Hello World is sent to the client)
and the destructor is invoked twice. A new client request will
invoke the destructor 15 times, functor will run (i.e Hello World is
sent to the client) and the destructor is invoked.... repeat.

I added the trivial destructor (see below) to the asynch_hello_world
example and I was stepping through the code I noticed the behavior -
which stepping through the code is predicated upon boost libraries
(boost::_bi::storageN - where N =1,2 and 3, boost::_bi::list,
boost::bi_bind). Could you elaborate on why I'm seeing multiple
destructor calls prior to invocation of the handler? Ineterestingly
enough a destructor call does not result in a call to the
constructor....so it's unclear what's happening.

~async_hello_world() {
std::cout << "." ;
}

Dean Michael Berris

unread,
Apr 22, 2012, 8:59:08 PM4/22/12
to cpp-n...@googlegroups.com
On Mon, Apr 23, 2012 at 6:48 AM, Mark <ma74...@gmail.com> wrote:
>
>
> On Apr 15, 8:53 pm, Dean Michael Berris <dber...@google.com> wrote:
>
>>
>> These are the offending lines:
>>
>> >        std::vector<boost::asio::const_buffer> iovec;
>> >        iovec.push_back(boost::asio::const_buffer( msg.c_str(), sz ) );
>> >        connection->write(iovec, boost::bind(&async_hello_world::error, this,
>> > _1));
>>
>> The problem here is that iovec doesn't own the memory pointed to by
>> the const_buffer instances. This means you are probably accessing
>> memory that's uninitialized or that's been re-used or something else.
>> What happens here is that when you do 'connection->write(...)' it
>> returns immediately and therefore the string owning the message is
>> destroyed. By the time the data is read/written to the socket it's
>> been deleted and therefore you're invoking undefined behavior.
>
> Dean, two things:
>
> a)
>
> How is that different than the example which reflects:
>
>        std::vector<boost::asio::const_buffer> iovec;
>        iovec.push_back(boost::asio::const_buffer(hello_world, 13));
>       connection->write(iovec, boost::bind(&async_hello_world::error,
> this, _1));
>

What example? Can you point me to where this is? Or are you talking
about the test?

https://github.com/cpp-netlib/cpp-netlib/blob/master/libs/network/test/http/server_async.cpp

If you look closely the string is a _static_ function local variable.
It doesn't change and lasts the program's lifetime. The difference
there is that the string is never copied and doesn't go out of scope
until the application actually exits.

> b)
>
> Upon receipt of a client request and prior to invocation of the
> functor ( asynch_hello_word example ) the destructor is invoked 15
> times.  The functor will run (ie Hello World is sent to the client)
> and the destructor is invoked twice.   A new client request will
> invoke the destructor 15 times, functor will run (i.e Hello World is
> sent to the client) and the destructor is invoked.... repeat.
>

This was a bug fixed by 'idleman' that's now in the 0.9.4 release.

> I added the trivial destructor (see below) to the asynch_hello_world
> example and I was stepping through the code I noticed the behavior -
> which stepping through the code is predicated upon boost libraries
> (boost::_bi::storageN - where N =1,2 and 3, boost::_bi::list,
> boost::bi_bind).   Could you elaborate on why I'm seeing multiple
> destructor calls prior to invocation of the handler?   Ineterestingly
> enough a destructor call does not result in a call to the
> constructor....so it's unclear what's happening.
>
>    ~async_hello_world() {
>      std::cout << "." ;
>    }
>

This is because the handler object is being copied around in the
completion handlers. This is no longer the case as I mentioned in
0.9.4 -- please use that version instead or if you're using the master
branch then please pull from the latest now.

Mark

unread,
Apr 23, 2012, 7:27:52 AM4/23/12
to The C++ Network Library


On Apr 22, 8:59 pm, Dean Michael Berris <dber...@google.com> wrote:
> What example? Can you point me to where this is? Or are you talking
> about the test?

libs\network\test\http\server_async_less_copy.cpp

// Copyright 2010 Dean Michael Berris.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#define BOOST_TEST_MODULE HTTP Asynchronous Server Tests

#include <vector>

#include <boost/config/warning_disable.hpp>
#include <boost/network/include/http/server.hpp>
#include <boost/network/utils/thread_pool.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <iostream>

namespace net = boost::network;
namespace http = boost::network::http;
namespace utils = boost::network::utils;

struct async_hello_world;
typedef http::async_server<async_hello_world> server;

struct async_hello_world {

struct is_content_length {
template <class Header>
bool operator()(Header const & header) {
return boost::iequals(name(header), "content-length");
}
};

void operator()(server::request const & request,
server::connection_ptr connection) {
static server::response_header headers[] = {
{"Connection", "close"}
, {"Content-Type", "text/plain"}
, {"Server", "cpp-netlib/0.9"}
, {"Content-Length", "13"}
};
static char const * hello_world = "Hello, World!";
connection->set_status(server::connection::ok);
connection->set_headers(boost::make_iterator_range(headers,
headers+4));
std::vector<boost::asio::const_buffer> iovec;
iovec.push_back(boost::asio::const_buffer(hello_world, 13));
connection->write(iovec,
boost::bind(&async_hello_world::error, this, _1));
}

void error(boost::system::error_code const & ec) {
// do nothing here.
}
};

int main(int argc, char * argv[]) {
utils::thread_pool thread_pool(2);
async_hello_world handler;
std::string port = "8000";
if (argc > 1) port = argv[1];
server instance("127.0.0.1", port, handler, thread_pool,
http::_reuse_address=true);
instance.run();
return 0;
}

Dean Michael Berris

unread,
Apr 23, 2012, 7:43:34 AM4/23/12
to cpp-n...@googlegroups.com
On Mon, Apr 23, 2012 at 9:27 PM, Mark <ma74...@gmail.com> wrote:
>
>
> On Apr 22, 8:59 pm, Dean Michael Berris <dber...@google.com> wrote:
>> What example? Can you point me to where this is? Or are you talking
>> about the test?
>
> libs\network\test\http\server_async_less_copy.cpp
>

For the record, this is not an example, this is part of the test
suite. If you want to see an example, look in libs/network/example.
Even if this is the case...

See both of these lines? They're saying the C string "hello_world" and
the response_header array "headers" are function-local static
variables. This means their lifetime is tied to the application's
lifetime, and not the object's lifetime. This is the difference
between your code and this code.

To see how you can approach this problem, look at the fileserver.cpp
example in libs/network/example/http/fileserver.cpp
(https://github.com/cpp-netlib/cpp-netlib/blob/master/libs/network/example/http/fileserver.cpp).

Cheers

--
Dean Michael Berris
www.deanberris.com

Mark

unread,
Apr 23, 2012, 1:52:21 PM4/23/12
to The C++ Network Library


On Apr 23, 7:43 am, Dean Michael Berris <mikhailbe...@gmail.com>
wrote:
>
> To see how you can approach this problem, look at the fileserver.cpp
> example in libs/network/example/http/fileserver.cpp
> (https://github.com/cpp-netlib/cpp-netlib/blob/master/libs/network/exa...).
>

Crud! I thought the static keyword was present in my initial post.
My mistake
Mark

Mark

unread,
Apr 28, 2012, 12:20:25 PM4/28/12
to The C++ Network Library


On Apr 23, 7:43 am, Dean Michael Berris <mikhailbe...@gmail.com>
wrote:
>
> To see how you can approach this problem, look at the fileserver.cpp
> example in libs/network/example/http/fileserver.cpp
> (https://github.com/cpp-netlib/cpp-netlib/blob/master/libs/network/exa...).

So I'm trying to mimick the example at link:
http://poco.svn.sourceforge.net/viewvc/poco/poco/branches/poco-1.4.4/ApacheConnector/samples/FormServer/src/FormServer.cpp?revision=1783&view=markup

I used the fileserver example as leverage except 'file_cache' is
renamed to 'form_handler' and the ostr object is constructed within
the constructor of the form_handler class. So now


struct form_handler {
unsigned int m_counter ;
std::ostringstream ostr;
static server::response_header common_headers[];
std::vector<server::response_header> headers ;
std::vector<boost::asio::const_buffer> iovec;
explicit form_handler()
: m_counter ( 0 )
, headers ( common_headers, common_headers+3 )
{
ostr <<
"<html>\n"
"<head>\n"
"<title>POCO Form Server Sample</title>\n"
"</head>\n"
"<body>\n"
"<h1>POCO Form Server Sample</h1>\n"
"<h2>GET Form</h2>\n"
"<form method=\"GET\" action=\"/form\">\n"
"<input type=\"text\" name=\"text\" size=\"31\">\n"
"<input type=\"submit\" value=\"GET\">\n"
"</form>\n"
"<h2>POST Form</h2>\n"
"<form method=\"POST\" action=\"/form\">\n"
"<input type=\"text\" name=\"text\" size=\"31\">\n"
"<input type=\"submit\" value=\"POST\">\n"
"</form>\n"
"<h2>File Upload</h2>\n"
"<form method=\"POST\" action=\"/form\" enctype=\"multipart/form-data
\">\n"
"<input type=\"file\" name=\"file\" size=\"31\"> \n"
"<input type=\"submit\" value=\"Upload\">\n"
"</form>\n";
}

// more functions .. get_header, destructructor ..

std::vector<boost::asio::const_buffer> get_data () {
iovec.clear();
/// std::string ss ( ostr.str() ) ; // ... ( ss.str(),
ss.size() )
iovec.push_back(boost::asio::const_buffer( ostr.str().c_str(),
ostr.str().size () ) );
return ( iovec ) ;
}

};

The connection handler class calls get_data and the contents sent,
except I'm seeing invalid characters with my browser or a 'poco'
client app. If i have a string object with - say "hello world"
there's no issues. i.e. I receive valid contents on the client side.

An ostringstream object produce invalid charcaters. osstringstream
stored as string (see ss above) produce invalid characters. All
looks well on the server side so it's not clear to me what the issue
is. Your thoughts

Mark


Divye Kapoor

unread,
Apr 28, 2012, 5:59:34 PM4/28/12
to cpp-n...@googlegroups.com
https://github.com/cpp-netlib/cpp-netlib/issues/69


--
You received this message because you are subscribed to the Google Groups "The C++ Network Library" group.
To post to this group, send email to cpp-n...@googlegroups.com.
To unsubscribe from this group, send email to cpp-netlib+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/cpp-netlib?hl=en.


Reply all
Reply to author
Forward
0 new messages