MySQL Forums
Forum List  »  Connector/C++

read access violation in xdevapi 8.0.17
Posted by: John Cuyle
Date: November 20, 2019 04:57PM

I keep seeing an access violation in the MySQL dll. It appears to be random, not 100% of the time, but happens frequently. Originally I thought that I was allowing the session to be destroyed before the results, but I created a small wrapper to ensure that results are always destroyed before the session.

Here's the snippet of my most relevant code. I'm not sure that this is the function that's failing (unfortunately putting breakpoints in changes the timing enough that it significantly reduces the chances of this happening.) You can see that I create move-construct the session into a shared_ptr, construct the Statement for later execution, pass the shared_ptr to query which executes the statement on a thread in my thread pool, and pack the results into a shared pointer (since results don't seem to be copyable but are movable) and a copy of the shared_ptr to the session into a simple result wrapper. The wrapper exists to be copyable and to ensure that the last shared_ptr to the results is released before the last shared_ptr to the session, ensuring that the session's lifespan is longer than the results. I'm not sure all this should strictly speaking be necessary, but I've been chasing this null pointer exception for a while and since the null pointer being dereferenced is the session, I sort of assumed that I was allowing the session to be destroyed before the results. Maybe there's a bug in this code, but it ought to guarantee that the session is not destroyed before the results, and indeed when I look at it in my debugger my session shared pointer is valid.

template< typename Result >
class result_ptr
{
public:
using result_t = Result;

private:
std::shared_ptr< result_t > Result_;
std::shared_ptr< msx::Session > Session_;

public:
result_ptr( ) { }

result_ptr( result_t && result, decltype( Session_ ) session ) :
Result_( std::make_shared< result_t >( std::move( result ) ) ),
Session_( session )
{ }

~result_ptr( )
{
Result_.reset( );
Session_.reset( );
}

result_ptr( result_ptr && ) = default;
result_ptr( result_ptr const & ) = default;

result_ptr & operator=( result_ptr && ) = default;
result_ptr & operator=( result_ptr const & ) = default;

auto & operator*( ) const noexcept
{
return *Result_;
}

auto operator->( ) const noexcept
{
return Result_.get( );
}
};

template< typename Exec >
inline auto query( ContextId const &, std::shared_ptr< msx::Session > session, Exec statement ) -> ppl::task< result_ptr< decltype( statement.execute( ) ) > >
{
return ppl::create_task(
[session, s = std::make_shared< Exec >( std::move( statement ) )]( )
{
try
{
return result_ptr< decltype( s->execute( ) ) >( s->execute( ), session );
}
catch( std::exception const & ex )
{
so::cout << ex.what( ) << "\n";
throw;
}
} );
};

ppl::task< std::vector< TaskId > > MySQLQueue::getReadyTasks(
ContextId const & contextId,
unsigned int const limit )
{
using result_type = decltype( u::query( contextId, std::shared_ptr< msx::Session >( ), Client_.getSession( ).getSchema( "" ).getTable( "" ).select( ) ) )::result_type;

auto session = std::make_shared< msx::Session >( Client_.getSession( ) );

return u::query(
contextId,
session,
session->getSchema( SchemaName_ ).getTable( TableName_
).select(
info::column::select[info::column::_id]
).where(
"state = :state AND processAfter < :processAfter"
).limit(
limit
).bind( std::map< std::string, std::string >{
{ "state", Info::State::String[Info::State::Created] },
{ "processAfter", utility::time_point_to_string( clock::now( ) ) } }
)
).then(
[]( result_type const & res )
{
std::vector< TaskId > rv;
rv.reserve( res->count( ) );

std::transform(
res->begin( ),
res->end( ),
std::back_inserter( rv ),
[]( msx::Row && row ) -> TaskId
{
return std::to_string( row[0].get< uint64_t >( ) );
} );

return rv;
} );
}

I cannot figure out why this is resulting in an access violation. The AV error message when the exception is trapped is:

Exception thrown: read access violation.
this->m_session was nullptr.

You can see from the call stack that the AV is actually buried pretty deep in the MySQL dll:

mysqlcppconn8-2-vs14.dll!cdk::mysqlx::Reply::has_results() Line 132 C++
mysqlcppconn8-2-vs14.dll!cdk::mysqlx::Reply::discard() Line 102 C++
mysqlcppconn8-2-vs14.dll!cdk::mysqlx::Reply::~Reply() Line 59 C++
mysqlcppconn8-2-vs14.dll!cdk::Reply::~Reply() C++
mysqlcppconn8-2-vs14.dll!cdk::Reply::`scalar deleting destructor'(unsigned int) C++
mysqlcppconn8-2-vs14.dll!mysqlx::abi2::r0::common::Result_impl::~Result_impl() Line 181 C++
mysqlcppconn8-2-vs14.dll!mysqlx::abi2::r0::common::Result_impl::`scalar deleting destructor'(unsigned int) C++
mysqlcppconn8-2-vs14.dll!mysqlx::abi2::r0::internal::Result_detail::~Result_detail() Line 493 C++
cgrmerge.exe!mysqlx::abi2::r0::internal::Result_common<mysqlx::abi2::r0::internal::Result_detail>::~Result_common<mysqlx::abi2::r0::internal::Result_detail>() C++
cgrmerge.exe!mysqlx::abi2::r0::Result::~Result() C++
cgrmerge.exe!mysqlx::abi2::r0::Result::`scalar deleting destructor'(unsigned int) C++
cgrmerge.exe!std::_Destroy_in_place<mysqlx::abi2::r0::Result>(mysqlx::abi2::r0::Result & _Obj) Line 322 C++
cgrmerge.exe!std::_Ref_count_obj2<mysqlx::abi2::r0::Result>::_Destroy() Line 1506 C++
cgrmerge.exe!std::_Ref_count_base::_Decref() Line 652 C++
cgrmerge.exe!std::_Ptr_base<mysqlx::abi2::r0::Result>::_Decref() Line 883 C++
> cgrmerge.exe!std::shared_ptr<mysqlx::abi2::r0::Result>::~shared_ptr<mysqlx::abi2::r0::Result>() Line 1133 C++
cgrmerge.exe!std::shared_ptr<mysqlx::abi2::r0::Result>::reset() Line 1178 C++
cgrmerge.exe!utility::result_ptr<mysqlx::abi2::r0::Result>::~result_ptr<mysqlx::abi2::r0::Result>() Line 60 C++
cgrmerge.exe!pplx::details::_ResultHolder<utility::result_ptr<mysqlx::abi2::r0::Result>>::~_ResultHolder<utility::result_ptr<mysqlx::abi2::r0::Result>>() C++
cgrmerge.exe!pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>::~_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>() Line 2432 C++
cgrmerge.exe!pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>::`scalar deleting destructor'(unsigned int) C++
cgrmerge.exe!std::_Destroy_in_place<pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>>(pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>> & _Obj) Line 322 C++
cgrmerge.exe!std::_Ref_count_obj2<pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>>::_Destroy() Line 1506 C++
cgrmerge.exe!std::_Ref_count_base::_Decref() Line 652 C++
cgrmerge.exe!std::_Ptr_base<pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>>::_Decref() Line 883 C++
cgrmerge.exe!std::shared_ptr<pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>>::~shared_ptr<pplx::details::_Task_impl<utility::result_ptr<mysqlx::abi2::r0::Result>>>() Line 1133 C++
cgrmerge.exe!pplx::task<utility::result_ptr<mysqlx::abi2::r0::Result>>::_ContinuationTaskHandle<utility::result_ptr<mysqlx::abi2::r0::Result>,utility::result_ptr<mysqlx::abi2::r0::Result>,`ScheduledTask::MySQLQueue::recover'::`2'::<lambda_1>,std::integral_constant<bool,0>,pplx::details::_TypeSelectorAsyncTask>::~_ContinuationTaskHandle<utility::result_ptr<mysqlx::abi2::r0::Result>,utility::result_ptr<mysqlx::abi2::r0::Result>,`ScheduledTask::MySQLQueue::recover'::`2'::<lambda_1>,std::integral_constant<bool,0>,pplx::details::_TypeSelectorAsyncTask>() Line 3871 C++
cgrmerge.exe!pplx::task<utility::result_ptr<mysqlx::abi2::r0::Result>>::_ContinuationTaskHandle<utility::result_ptr<mysqlx::abi2::r0::Result>,utility::result_ptr<mysqlx::abi2::r0::Result>,`ScheduledTask::MySQLQueue::recover'::`2'::<lambda_1>,std::integral_constant<bool,0>,pplx::details::_TypeSelectorAsyncTask>::`scalar deleting destructor'(unsigned int) C++
cgrmerge.exe!pplx::details::_AutoDeleter<pplx::details::_TaskProcHandle>::~_AutoDeleter<pplx::details::_TaskProcHandle>() Line 99 C++
cgrmerge.exe!pplx::details::_TaskProcHandle::_RunChoreBridge(void * _Parameter) Line 117 C++
cpprest141d_2_10.dll!pplx::details::_Scheduler_Param::DefaultWorkCallback(struct _TP_CALLBACK_INSTANCE *,void *,struct _TP_WORK *) Unknown
ntdll.dll!TppWorkpExecuteCallback() Unknown
ntdll.dll!TppWorkerThread() Unknown
kernel32.dll!BaseThreadInitThunk() Unknown
ntdll.dll!RtlUserThreadStart() Unknown

Any help would be greatly appreciated.

Options: ReplyQuote


Subject
Views
Written By
Posted
read access violation in xdevapi 8.0.17
685
November 20, 2019 04:57PM


Sorry, you can't reply to this topic. It has been closed.

Content reproduced on this site is the property of the respective copyright holders. It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.