Repository navigation
Conversation
|
Can you give a case it fails? How it fixes the issue? I tried setting small page sizes and it all works. Also I don't see the bug here. The idea is following if it is a long string allocate a separate page for it, otherwise use paged pool. |
|
I also rerun some cases with small buffer size with valgrind to see if anythonig shows up and it does not. Can you please explain the fix and what it fixes. |
|
The reason for size * 2 - is to prevent wasting too much memory for large strings. |
|
The problem is the case were the size is between page size and 2 * page size. It's too small to allocate an own page with the correct size ( > 2 * page size case). Then depending on the size it allocates a new page or uses an existing page. But since the size is > page size it always writes the string out of bounds because a page has a maximum size of page_size and that is smaller than size. |
|
Note that I don't know why it worked with CppCMS 1.2.1 (same code in string_map.h). But with CppCMS 2.0.1 we started experiencing problems in only one of our applications. I found the origin of the problem with Valgrind's memcheck. |
|
We also recently had a bug in our code that seems to be related to this. The allocation sequence tries to simulate what the HTTP connector does per request: // g++ -std=c++11 -g -fsanitize=address repro_lib.cpp -o repro_lib \
// -I<cppcms-src>/private -I<cppcms-install>/include
#include <string>
#include <vector>
#include "string_map.h" // the real cppcms header, unmodified
using cppcms::impl::string_pool;
typedef std::vector<std::pair<std::string, std::string> > headers_t;
static void serve_request(string_pool &pool, const headers_t &headers)
{
pool.clear();
pool.add("127.0.0.1");
pool.alloc(10);
for(size_t i = 0; i < headers.size(); i++) {
pool.alloc(headers[i].first.size() + 1);
pool.alloc(headers[i].second.size() + 1);
}
}
int main()
{
string_pool pool;
headers_t req;
req.push_back(std::make_pair("host", "localhost"));
req.push_back(std::make_pair("connection", "keep-alive"));
req.push_back(std::make_pair("cookie", "sid=" + std::string(1200, 'A'))); // >1024 -> own page
for(int i = 0; i < 15; i++) // ordinary headers
req.push_back(std::make_pair("x-header", std::string(120, 'v')));
serve_request(pool, req); // request N
serve_request(pool, req); // request N+1 on same keep-alive connection -> overflow
return 0;
}AddressSanitizer: It triggers whenever a request stores a single pooled string larger than Reproducing against a running server (curl)Point a server at The worker crashes on the second request. A single URL (one request, connection |
Wow reproduced! serious bug indeed. Thanks! I'm going to work on it ASAP! |
|
I feel dump on this code: It was incorrect pool cleanup - totally messed up! How could I write this broken code?! I fixed it in master branch now it works and does not crash Thanks for the way to reproduce it! It was of enromous help. I'll live PL for few days opened for discussion of this horrible bug. I'll close it later (since the fix is different) |
|
And added ,memory leak fix |
in the case where size is between page_size and 2 * page_size.