0

In some rare cases (in fact on a single client's computer) code below throws an exception "library_error":

namespace ipc = boost::interprocess;
ipc::shared_memory_object m_shm;
...
bool initAsServer(size_t sharedMemSize)
{
    ipc::permissions perm;
    perm.set_unrestricted();

    try
    {
        m_shm = ipc::shared_memory_object(
            ipc::create_only,
            CNameGenHelper::genUniqueNameUtf8().c_str(), // static std::string genUniqueNameUtf8()
            ipc::read_write, perm);
    }
    catch(const ipc::interprocess_exception& ex)
    {
        logError("failed with exception \"%s\"", ex.what());
        return false;
    }
    ...
}

In log file: [ERR] failed with exception "boost::interprocess_exception::library_error"

Boost v1.58, platform win32, vs13.


I'll be very grateful if you help me in solving this problem. Thank you in advance!

Oleg
  • 51
  • 1
  • 1
  • 5
  • Are you checking if the shared memory segment already exists in the system ? – Arunmu Jun 27 '16 at 10:39
  • No, this is not necessary since the function CNameGenHelper::genUniqueNameUtf8() generates a unique name based on the GUID. I added to the log file getting error codes via ex.get_error_code() and ex.get_native_error() for additional exception information. Now I wating for log files from client side... Thank you for your interest in this issue! – Oleg Jun 28 '16 at 04:30
  • for updated line in catch: logError("failed with exception \"%s\", error %d, native error %d", ex.what(), ex.get_error_code(), ex.get_native_error()); --- In log file: [ERR] failed with exception "boost::interprocess_exception::library_error", error 1, native error 0. --- error 1 - system_error (from enum error_code_t) Help me please... – Oleg Jul 06 '16 at 01:45
  • Note: I'm trying to to allocate a relatively small amount of memory, only ~8 MB. – Oleg Jul 06 '16 at 01:50
  • Why dont you step through a debugger in the function ? That would surely help you find the code where its throwing the exception. – Arunmu Jul 06 '16 at 06:25
  • I can not use the debugger on the client (customer) computer. – Oleg Jul 07 '16 at 07:06

3 Answers3

3

Reason of problem is events with Event ID = "6005" and source name is "EventLog" in "System" Windows log. Event Viewer - Windows Logs - System. If the system log does not contain at least one such event, then method boost::interprocess::winapi::get_last_bootup_time() returns false and boost::interprocess::ipcdetail::windows_bootstamp constructor throws exception. (define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME is used).

So it seems that it is enough to clear the "System" windows event log and any application that uses the Boost shared memory will stop working.

What a terrible logic: use the contents of the windows event log. It seems this boost ipc implementation bug that has not yet been fixed (boost_1_61_0).

My temporary workaround for this case (w/o reboot of computer):

bool fixBoostIpcSharedMem6005issue() const
{
    bool result = false;

    HANDLE hEventLog = ::RegisterEventSourceA(NULL, "EventLog");
    if(hEventLog)
    {
        const char* msg = "simple boost shared memory fix for 6005";

        if(::ReportEventA(hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 6005, NULL, 1, 0, &msg, NULL))
            result = true;

        ::DeregisterEventSource(hEventLog);
    }

    return result;
}

Use it and try to use ipc::shared_memory_object again :)

Oleg
  • 51
  • 1
  • 1
  • 5
1

Many detailed explanations about by the problem, by one of the authors of the library: Boost interprocess: Getting boot-up time is unreliable on Windows and here: Interprocess get_last_bootup_time use of Event Log on Windows is completely unreliable

Apparently, a reliable solution is to define the preprocessor constant BOOST_INTERPROCESS_SHARED_DIR_PATH to a function call, which always returns the same directory path as a string, once the machine is booted. For example by formatting the update time-stamp of a file, written to at start-up.

remi.chateauneu
  • 109
  • 2
  • 9
1

You can #define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED or BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME to switch to either registry or WMI based boot time detection. Alternatively, you can use BOOST_INTERPROCESS_SHARED_DIR_PATH, but it's kind of useless on Windows since it uses hardcoded path. BOOST_INTERPROCESS_SHARED_DIR_FUNC is much better option since it lets you define a function that returns path to the shared directory.

imagi
  • 946
  • 8
  • 8