3

I'm having some troubles with Boost.Interprocess allocators when compiling with optimization. I managed to get this down to a 40 lines testcase, most of which is boilerplate. Just have a look at create() and main() functions in the code below.

#include <iostream>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace interp = boost::interprocess;

struct interp_memory_chunk
{
  interp::managed_shared_memory  chunk;

  interp_memory_chunk ()
  {
    interp::shared_memory_object::remove ("GCC_interprocess_test");
    chunk = interp::managed_shared_memory (interp::create_only, "GCC_interprocess_test", 0x10000);
  }

  ~interp_memory_chunk ()
  {
    interp::shared_memory_object::remove ("GCC_interprocess_test");
  }
};

typedef  interp::allocator <int, interp::managed_shared_memory::segment_manager>  allocator_type;

inline  void
create (allocator_type& allocator, allocator_type::value_type& at, int value)
{
  allocator.construct (allocator.address (at), value);
}

int
main ()
{
  interp_memory_chunk      memory;
  allocator_type           allocator (memory.chunk.get_segment_manager ());
  allocator_type::pointer  data = allocator.allocate (1);

  create (allocator, *data, 0xdeadbeef);
  std::cout << std::hex << *data << "\n";
}

When compiling this without optimization:

g++ interprocess.cpp -lboost_thread -o interprocess

and running, the output is deadbeef, as expected.

However, when compiling with optimization:

g++ -O1 interprocess.cpp -lboost_thread -o interprocess

running gives 0, not what is expected.

So, I'm not sure where the problem is. Is this a bug in my program, i.e. do I invoke some UB? Is it a bug in Boost.Interprocess? Or maybe in GCC?

For the record, I observe this behavior with GCC 4.6 and 4.5, but not with GCC 4.4 or Clang. Boost version is 1.46.1 here.

EDIT: Note that having create() as a separate function is essential, which might indicate that problem arises when GCC inlines it.

  • strange, when i replace -O1 with their alleged equivalent optimization flags, it gives deadbeef. – BatchyX Nov 19 '11 at 16:30
  • try using open_or_create instead of create_only? – SoapBox Nov 19 '11 at 19:28
  • 2
    ...also, try having a look at the assembly and see what's different. – SoapBox Nov 19 '11 at 19:29
  • +1 for checking the assembler, especially between -O1 and apparent equivalent optimisation flags. – James Nov 19 '11 at 20:10
  • Unfortunately, I lack skills to understand assembler. –  Nov 20 '11 at 11:37
  • Testing shows that with Boost 1.48 it works as expected, with or without optimization. –  Nov 20 '11 at 13:43
  • @Batch replacing -O1 with the "equivalent optimization flags" doesn't do anything because, without -O1, optimization is not enabled. – ams Nov 28 '11 at 09:13
  • @Autopulated see my reply to BatchyX - "equivalent options" are a misconception - most (but not all) are not meaningful until optimization is enabled. However, "-O1 -fno-whatever" is meaningful. Note that some optimizations are not associated with a flag at all. – ams Nov 28 '11 at 09:23
  • I would say that the optimized part is running too fast.In the class constructor you're calling a function to destroy interprocess shared memory (have you checked that it isn't throwing exceptions?) and then create in the next line. Boost can do that by using a file, kernel calls, etc. I find it likely that it happens too fast - for instance, if Boost is using files, the kernel lock on it may not be released yet when you try to create the next one in the very next command. See if a call to boost::this_thread::sleep(boost::posix_time::milliseconds(10)) in theconstructor between the two fixes it – std''OrgnlDave Jan 17 '12 at 05:23

1 Answers1

0

As others have suggested, one solution is try to find the minimial set of optimisation flags you need to trigger your problem, using -O1 -fno....

Other options:

  1. Use Valgrind and see what it comes up with

  2. Try compiling with "-fdump-tree-all", this generates a bunch of intermediate compiled files. You can then see if the compiled code has any differences. These intermediate files are still in C++, so you don't need to know assembler. They are pretty much human readable, and certainly diffable.

junichiro
  • 5,282
  • 3
  • 18
  • 26