Project

General

Profile

Wt::Dbo strange segfault when find<C>.where().bind()

Added by Valeriy Fedyunin over 8 years ago

Hello!

The following code results in segfault.

std::shared_ptr<CStatQueryCache> Session::getStatQueryCache( int indexId, int64_t searchLimit, std::string structureCqlSta )
{
    std::shared_ptr<CStatQueryCache> result( nullptr );
    dbMutex.lock();
    try {
        Wt::Dbo::Transaction transaction(session_);
        Wt::Dbo::ptr<CStatQueryCache> dboObject = session_.find<CStatQueryCache>().
            where("structure_cql_sta = ?").
            bind( structureCqlSta ).
            where("index_id = ?").
            bind( indexId ).
            where("search_limit = ?").
            bind( searchLimit );
        if( dboObject.get() != nullptr ) {
            result = std::shared_ptr<CStatQueryCache>( new CStatQueryCache( *(dboObject.get()) ) );
        }
    } catch( Wt::Dbo::Exception& ex ) {
        std::wcerr << "Session::getStatQueryCache: " << ex.what() << std::endl;
    }
    dbMutex.unlock();
    return result;
}

Parameters for segfault (from gdb call stack):

indexId = 25;
searchLimit = 9882120;
structureCqlSta = "[gender=\"NA\"]";

and this line exists in mapped CStatQueryCache table.

Backend - Postgres.

The most interesting things:

- adding dbmutex (which you can see in the code) for all operations wchich require transaction didn't help

  • when I added breakpoint to the first line of the function and went through the function with debugger line -by-line it worked correctly.

Stack trace

malloc_consolidate (av=0x7ffff45c2760 <main_arena>, av@entry=0x7ffff45c2760 <main_arena>)   
_int_free (av=0x7ffff45c2760 <main_arena>, p=<optimized out>, have_lock=0)  
CRYPTO_free ()  
EVP_CIPHER_CTX_cleanup ()   
?? ()   
SSL_free () 
?? ()   
?? ()   
?? ()   
?? ()   
PQgetResult ()  
?? ()   
Wt::Dbo::backend::Postgres::startTransaction (this=<optimized out>) 
Wt::Dbo::Session::connection (this=0x7ffa8000be20, openTransaction=true, openTransaction@entry=true)    
Wt::Dbo::Session::getStatement (this=<optimized out>, id=@0x7ffa7cff85a0: {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa60002488 \"select \\\"id\\\", \\\"version\\\", \\\"structure_cql_sta\\\", \\\"index_id\\\", \\\"search_limit\\\", \\\"count\\\" from \\\"stat_query_cache\\\"  where (structure_cql_sta = ?) and (index_id = ?) and (search_limit = ?)\"}})   
Wt::Dbo::Session::getOrPrepareStatement (this=0x7ffa8000be20, sql=@0x7ffa7cff85a0: {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa60002488 \"select \\\"id\\\", \\\"version\\\", \\\"structure_cql_sta\\\", \\\"index_id\\\", \\\"search_limit\\\", \\\"count\\\" from \\\"stat_query_cache\\\"  where (structure_cql_sta = ?) and (index_id = ?) and (search_limit = ?)\"}})  
Wt::Dbo::Impl::QueryBase<Wt::Dbo::ptr<CStatQueryCache> >::statements (this=0x7ffa7cff87e0, where=@0x7ffa7cff8810: {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa60000c98 \"(structure_cql_sta = ?) and (index_id = ?) and (search_limit = ?)\"}}, groupBy=@0x7ffa7cff8818: {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffff500e738 <std::string::_Rep::_S_empty_rep_storage+24> \"\"}}, orderBy=@0x7ffa7cff8820: {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffff500e738 <std::string::_Rep::_S_empty_rep_storage+24> \"\"}}, limit=-1, offset=-1)  
Wt::Dbo::Query<Wt::Dbo::ptr<CStatQueryCache>, Wt::Dbo::DynamicBinding>::resultList (this=0x7ffa7cff87e0)    
Wt::Dbo::Query<Wt::Dbo::ptr<CStatQueryCache>, Wt::Dbo::DynamicBinding>::resultValue (this=0x7ffa7cff87e0)   
Wt::Dbo::Query<Wt::Dbo::ptr<CStatQueryCache>, Wt::Dbo::DynamicBinding>::operator Wt::Dbo::ptr<CStatQueryCache> (this=0x7ffa7cff87e0)    
Session::getStatQueryCache (this=0x7ffa8000bd88, indexId=25, searchLimit=9882120, structureCqlSta={static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa60000908 \"[gender=\\\"NA\\\"]\"}})   
WTSnippetWidget::runStatQuery (this=0x7ffa744a9440, indexId=25, query={static npos = 18446744073709551615, _M_dataplus = {<std::allocator<wchar_t>> = {<__gnu_cxx::new_allocator<wchar_t>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa60000938 L\"[gender=\\\"NA\\\"]\"}}, docLimit=9882120, docNum=9882120) 
WTSnippetWidget::runAttributeStatQueries (this=0x7ffa744a9440, attributeName={static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa7001b0d8 \"gender\"}}, attrValues={<std::_List_base<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {_M_impl = {<std::allocator<std::_List_node<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>}, _M_node = {_M_next = 0x7ffa700228c0, _M_prev = 0x7ffa70024a60}}}, <No data fields>}, corpusesIds={<std::_Vector_base<int, std::allocator<int> >> = {_M_impl = {<std::allocator<int>> = {<__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>}, _M_start = 0x7ffa70024ba0, _M_finish = 0x7ffa70024bb4, _M_end_of_storage = 0x7ffa70024bb4}}, <No data fields>}, currentQuery={<std::__shared_ptr<CQuery, (__gnu_cxx::_Lock_policy)2>> = {_M_ptr = 0x7ffa70024630, _M_refcount = {_M_pi = 0x7ffa70022840}}, <No data fields>}, subqueries={<std::_Vector_base<CQuerys, std::allocator<CQuerys> >> = {_M_impl = {<std::allocator<CQuerys>> = {<__gnu_cxx::new_allocator<CQuerys>> = {<No data fields>}, <No data fields>}, _M_start = 0x7ffa70022590, _M_finish = 0x7ffa700225e0, _M_end_of_storage = 0x7ffa700225e0}}, <No data fields>}, corpusSettings={<std::_Vector_base<CInclusionSettings, std::allocator<CInclusionSettings> >> = {_M_impl = {<std::allocator<CInclusionSettings>> = {<__gnu_cxx::new_allocator<CInclusionSettings>> = {<No data fields>}, <No data fields>}, _M_start = 0x7ffa70024bc0, _M_finish = 0x7ffa70024c88, _M_end_of_storage = 0x7ffa70024c88}}, <No data fields>}, sessionId={static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7ffa74002b78 \"w2u4B9p1FyqZNYub\"}}) 
std::_Mem_fn<void (WTSnippetWidget::*)(std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)>::operator()<std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string, void>(WTSnippetWidget*, std::string&&, std::list<std::string, std::allocator<std::string> >&&, std::vector<int, std::allocator<int> >&&, std::shared_ptr<CQuery>&&, std::vector<CQuerys, std::allocator<CQuerys> >&&, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >&&, std::string&&) const (this=0x7ffa70024f08, __object=0x7ffa744a9440) 
std::_Bind_simple<std::_Mem_fn<void (WTSnippetWidget::*)(std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)> (WTSnippetWidget*, std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)>::_M_invoke<0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul>) (this=0x7ffa70024e88) 
std::_Bind_simple<std::_Mem_fn<void (WTSnippetWidget::*)(std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)> (WTSnippetWidget*, std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)>::operator()() (this=0x7ffa70024e88) 
std::thread::_Impl<std::_Bind_simple<std::_Mem_fn<void (WTSnippetWidget::*)(std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)> (WTSnippetWidget*, std::string, std::list<std::string, std::allocator<std::string> >, std::vector<int, std::allocator<int> >, std::shared_ptr<CQuery>, std::vector<CQuerys, std::allocator<CQuerys> >, std::vector<CInclusionSettings, std::allocator<CInclusionSettings> >, std::string)> >::_M_run() (this=0x7ffa70024e70)    
?? ()   

If change the logic that this function will be called from some Wt-thread (e.g. from slot, which is connected to some button, not from manually created std::thread) it works fine.

Thnx for attention and help:)


Replies (5)

RE: Wt::Dbo strange segfault when find<C>.where().bind() - Added by Valeriy Fedyunin over 8 years ago

One more logical question:

in multithreading application (where some threads can try to do something with DB simultaneously) is it safe to use single Wt::Dbo::Session for a whole application?

RE: Wt::Dbo strange segfault when find<C>.where().bind() - Added by Wim Dumon over 8 years ago

No, that is not safe. Since your crash happens inside the postgres connector library, this is probably what you're doing?

Wim.

RE: Wt::Dbo strange segfault when find<C>.where().bind() - Added by Valeriy Fedyunin over 8 years ago

Hi!

In my case each WApplication has it's own Wt::Dbo::Session. But, each WApplication has some number of additional threads (manually created std::thread, not Wt) and these threads can do something with Db simultaneously.

Is there any way to organize it to be safe? Maybe mutex to all operations with db or smth like that? Or may be each thread must have it's own Wt::Dbo::Session?

RE: Wt::Dbo strange segfault when find<C>.where().bind() - Added by Valeriy Fedyunin over 8 years ago

And one more important thing: some of widgets use queryModels, which getting results on-line using this Wt::Dbo::Session and doesn't have Wt::Dbo::Transaction or mutex around them (is there any way to make QueryModel use dbSession with mutex, or better to create another session?)

RE: Wt::Dbo strange segfault when find<C>.where().bind() - Added by Wim Dumon over 8 years ago

Both approaches are OK: either a mutex or a Dbo::Session per thread.

Wt's widgets are not threadsafe. You must grab the session lock (WApplication::UpdateLock) before touching anything in the widget tree from a different thread.

Wim.

    (1-5/5)