1
votes

I have an C++ application that has a main thread and a Poco::Timer to trigger a callback which writes to a file using Poco::FileOutputStream:

FileOutputStream file("test.txt", ios::binary); <-- *Access violation reading location here*
file.write(reinterpret_cast<char *>(&data), sizeof(data));
file.close();

The code always failed at the first line, here is the call stack:

testProject.exe!std::ctype::widen(char _Byte=' ') Line 1716 + 0xf bytes C++ testProject.exe!std::basic_ios >::widen(char _Byte=' ') Line 126 C++ testProject.exe!std::basic_ios >::init(std::basic_streambuf > * _Strbuf=0x038ef700, bool _Isstd=false) Line 135 + 0xa bytes C++ testProject.exe!std::basic_ostream >::basic_ostream >(std::basic_streambuf > * _Strbuf=0x038ef700, bool _Isstd=false) Line 54 C++ testProject.exe!Poco::FileOutputStream::FileOutputStream(const std::basic_string,std::allocator > & path="c:\Projects\TestProject\test.txt", int mode=32) Line 93 + 0xa3 bytes C++ testProject.exe!OPC_Server::OnTimer(Poco::Timer & timer={...}) Line 3656 + 0x13 bytes C++ testProject.exe!Poco::TimerCallback::invoke(Poco::Timer & timer={...}) Line 212 + 0x14 bytes C++ testProject.exe!Poco::Timer::run() Line 197 + 0x19 bytes C++ testProject.exe!Poco::PooledThread::run() Line 200 + 0x15 bytes C++ testProject.exe!Poco::`anonymous namespace'::RunnableHolder::run() Line 57 + 0x17 bytes C++ testProject.exe!Poco::ThreadImpl::runnableEntry(void * pThread=0x00db6afc) Line 207 + 0x20 bytes C++ testProject.exe!_callthreadstartex() Line 348 + 0xf bytes C testProject.exe!_threadstartex(void * ptd=0x00db6d00) Line 331 C

Tracing into the stack, the timer thread seemed having problem reading the initialization _Byte at the top of the call stack in xlocale internal header:

_Elem __CLR_OR_THIS_CALL widen(char _Byte) const
    {   // widen char
        return (do_widen(_Byte)); <-- failed: Access violation reading location 
    }

Second entry in the stack in ios standard header:

_Elem __CLR_OR_THIS_CALL widen(char _Byte) const
    {   // convert _Byte to character using imbued locale
        const _Ctype& _Ctype_fac = _USE(getloc(), _Ctype);
        return (_Ctype_fac.widen(_Byte)); <-- call the top of the stack
    }

Third entry in the stack in ios standard header:

protected:
    void __CLR_OR_THIS_CALL init(_Mysb *_Strbuf = 0,
        bool _Isstd = false)
        {   // initialize with stream buffer pointer
        _Init();    // initialize ios_base
        _Mystrbuf = _Strbuf;
        _Tiestr = 0;
        _Fillch = widen(' '); <-- call the second entry

But very strangely, the same code runs fine without any error when being used on the main thread.

Is there any permission settings that I need to set for the Poco::Timer to be able to function properly? Or am I missing something very obvious? Thanks for any help.

EDIT: ----------------------

Poco version: 1.7.3

Platform: windows

1
My guess is that something in your program has undefined behaviour. Unfortunately, it's impossible to guess what or where. At least share the entirety of the callback function. (The most common problems are forgetting about synchronization between threads, and having threads access objects whose lifetime has ended.) - molbdnilo
@molbdnilo, the first peace of code in the callback is the ones that tries to write the file. it works perfectly fine when being called from the main thread that creates/starts the timer, but not the case when the timer invokes the callback from another(timer) thread... - zhywu
Yes, you already said that. The problem is not caused by those lines but by something else - the crash is only a symptom. Such is the glory of undefined behaviour. - molbdnilo
@molbdnilo, thanks for the comment, i've just tried a clean new project with just the timer and the callback to write a file, it works as expected. I will try to pinpoint the problem in my project - zhywu

1 Answers

0
votes

It turns out that the application exits immediately after the timer is created, but the exit is not cleanly done so it appears that the app is still running and the timer is still ticking, when actually some of the resource has already been released, which causes the error.

MS's _tmain() does something extra than main() apparently.

Sorry it is not _tmain(), but _tmainCRTStartup that is calling _tmain(). When _tmain() exits, other clean up code is run, my project isn't terminated somehow and the application appears still "running".