Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.
The Intel sign-in experience has changed to support enhanced security controls. If you sign in, click here for more information.

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.