[odb-users] odb crashes when querying object with section
Anton Paymyshev
anton.paymyshev at gmail.com
Tue May 23 04:22:22 EDT 2017
Hello,
I'm having issues with
odb 2.5.0.a11
sqlite 3.13.0
vs2015 update 3
windows 10
both release and debug
Schema and code below.
Test case requires two runs.
On the first run sqlite database file is created and filled with a single
row.
On the second run it tries to query that single row and crashes in
*result.begin() line, crash stack(note garbage in capacity argument value)
is similar to:
KernelBase.dll!_RaiseException at 16() Unknown
> vcruntime140.dll!_CxxThrowException(void * pExceptionObject=0x008ff654,
const _s__ThrowInfo * pThrowInfo=0x0f73a2fc) Line 131 C++
odb-2.5.dll!__scrt_throw_std_bad_alloc() Line 33 C++
odb-2.5.dll!operator new(unsigned int size=0xcdcdcdcd) Line 19 C++
odb-2.5.dll!odb::details::basic_buffer_base::capacity(unsigned int
c=0xcdcdcdcd, unsigned int data_size=0x00000000) Line 21 C++
odbbugtest.exe!odb::sqlite::object_result_impl<Test>::load_image() Line
132 C++
odbbugtest.exe!odb::sqlite::object_result_impl<Test>::load_id() Line 95
C++
odbbugtest.exe!odb::object_result_impl<Test>::load() Line 25 C++
My analysis:
- db->query<Test>() line runs object_statements<Test> construction which
leaves image_ field filled with garbage from heap. (Test case requires
"prepared" heap to be reproducible in release build)
- then object_result_impl<Test>::load_image() gets "truncated" result from
"statement_->load()" and goes to access::object_traits_impl< ::Test,
id_sqlite >::grow which tries to set sec1_value capacity to previously
uninitialized value(0xcdcdcdcd).
//-----schema (Schema.h):
#include <odb/core.hxx>
#include <odb/section.hxx>
#pragma db object
class Test
{
public:
#pragma db id
unsigned long id;
std::string str;
#pragma db section(mysection)
std::string sec1;
#pragma db load(lazy)
odb::section mysection;
};
//-----code (main.cpp):
#include <odb/sqlite/database.hxx>
#include <odb/schema-catalog.hxx>
#include <odb/query.hxx>
#include "Schema-odb.hxx"
int main()
{
std::unique_ptr<odb::sqlite::database> db;
odb::connection_ptr c;
try
{
db.reset(new odb::sqlite::database(L"test.db", SQLITE_OPEN_READWRITE));
c = db->connection();
}
catch (odb::exception &) //first run goes here, setup schema and a single
Test row
{
db.reset(new odb::sqlite::database(L"test.db", SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE));
c = db->connection();
odb::transaction t(c->begin());
odb::schema_catalog::create_schema(*db);
Test test;
test.id = 12345;
test.str = std::string(1024, 'x'); // comment that line and test case runs
OK
db->persist(test);
t.commit();
return 0;
}
odb::transaction t(c->begin());
{ // fill heap with garbage
for (auto i = 1; i < 10240; ++i)
std::vector<unsigned int> ttt(i, 0xcdcdcdcd);
}
auto result = db->query<Test>(odb::query<Test>::id == 12345);
auto &row = *result.begin(); // <--- crash here
//ASSERT(row.id == 12345)
t.commit();
return 0;
}
More information about the odb-users
mailing list