Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.
2430 Discussions

GCC 6.X, dead store elimination (DSE) optimises away memset in allocate_scheduler, causes run-time errors (bug in TBB)


This should be happening with almost any GCC 6 version for the last year.

The following fragment has issues:

111 public:
112     static generic_scheduler* allocate_scheduler( market& m ) {
113         void* p = NFS_Allocate(1, sizeof(scheduler_type), NULL);
114         std::memset(p, 0, sizeof(scheduler_type));
115         scheduler_type* s = new( p ) scheduler_type( m );
116         s->assert_task_pool_valid();
117         ITT_SYNC_CREATE(s, SyncType_Scheduler, SyncObj_TaskPoolSpinning);
118         return s;
119     }

Here std::memset is optimised away because marked as dead. This happens because according to C++ standard it does not effect objects life-time. The problem here is that TBB classes (e.g., generic_scheduler and scheduler) does not contain default values. There are a few things that on compiler side resolves the issue, e.g. -fno-builtin-memset (will force GCC not to optimise away memset), -flifetime-dse=1 or -fno-lifetime-dse. But this is an issue within TBB, thus better to fix it in the code.

GCC bugzilla item:

0 Kudos
1 Reply

Thanks for the information David.

We will add a workaround with -flifetime-dse=1 to our makefiles, and later we'll see if the issue should be addressed in a different way. To be honest, I am not sure if anything else should be done though. Constructing an object in a zero-initialized memory seems a perfectly fine technique to me, and removal of pre-lifetime stores is questionable. In particular, the standard says in 3.8/5 that it's OK to use the obtained address as void*, and neither of the cases of undefined behavior described there seemingly apply. In particular, the code does not interpret the address as a valid pointer to an object, and does not access non-static data members (i.e. I do not think that filling the memory counts as such). So I tend to think that using memset before running an in-place constructor is OK from the C++ standard viewpoint, and so GCC should have not thrown it away without even giving a warning.