Corvusoft / restbed

Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.
http://www.corvusoft.co.uk
Other
1.93k stars 377 forks source link

When the URI is very long, there will be a crash(segmentation fault) #473

Open sotex opened 3 years ago

sotex commented 3 years ago

In this parse_request_line function, use std::regex to extract request information.

https://github.com/Corvusoft/restbed/blob/55009b43618c2d3a0e2afad5fd845eddd964816b/source/corvusoft/restbed/detail/service_impl.cpp#L699-L721

I tested g++10(libstdc++) and clang+=10(libc++) to compile. When the URI is too long, it will crash. I will put the test code behind.

$ g++ --version
g++ (GCC) 10.2.0

$ clang++ --version
clang version 11.1.0
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

If use the boost::regex library(1.73 laster) to implement this function, I tested it will not crash, so this should be a problem with the std::regex library implementation.

test code

#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>

#if USE_BOOST
#include <boost/regex.hpp>
using namespace boost;
#else
#include <regex>
#endif

using namespace std;

// source/corvusoft/restbed/detail/service_impl.cpp
const map<string, string> parse_request_line(istream &stream)
{
    smatch matches;
    static const regex pattern("^([0-9a-zA-Z]*) ([a-zA-Z0-9:@_~!,;=#%&'\\-\\.\\/\\?\\$\\(\\)\\*\\+]+) (HTTP\\/[0-9]\\.[0-9])\\s*$");
    string data = "";
    getline(stream, data);

    cout << __func__ << ":" << __LINE__ << endl;
    if (not regex_match(data, matches, pattern) or matches.size() not_eq 4)
    {
        throw runtime_error("Your client has issued a malformed or illegal request status line. That’s all we know.");
    }
    cout << __func__ << ":" << __LINE__ << endl;

    const string protocol = matches[3].str();
    const auto delimiter = protocol.find_first_of("/");

    return map<string, string>{
        {"path", matches[2].str()},
        {"method", matches[1].str()},
        {"version", protocol.substr(delimiter + 1)},
        {"protocol", protocol.substr(0, delimiter)}};
}

int main()
{
    try
    {
        stringstream ss;
        ss << "GET ";
        ss << "/path?";
        for (size_t i = 0; i < 345; ++i)
        {
            ss << "key=%2F0123456789%2Fabcdefghigklmnopqrstuvwxyz%2FABCDEFGHIGKLMNOPQRSTUVWXYZ&";
        }
        ss << " HTTP/1.1";

        auto items = parse_request_line(ss);
        cout << "method = " << items["method"] << endl;
        cout << "version = " << items["version"] << endl;
        cout << "protocol = " << items["protocol"] << endl;
    }
    catch (std::exception e)
    {
        cout << e.what() << endl;
    }
    return 0;
}

gdb

Starting program: /tmp/test 
parse_request_line:20

Program received signal SIGSEGV, Segmentation fault.
0x000055555557f6e8 in std::__detail::_BracketMatcher<std::__cxx11::regex_traits<char>, false, false>::operator()(char) const ()
ben-crowhurst commented 3 years ago

We'll take a look during the upcoming 4.8 release.