Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Bastian_B_
New Contributor I
93 Views

OpenMP Crash at -O0 but not at -O2 when using threadprivate class instance with virtual functions

Hello,

The following code:

#include <iostream>
#include <omp.h>

class Base {
public:
  int memb_base;
  virtual int foo() { return 0; }
};

class Derived : public Base {
public:
  int memb_derived;
  virtual int foo() { return 1; }
};

class Container {
public:
  Derived* Get_d() { return &_d; }
  void print() {
    #pragma omp critical
    {
      Derived* p = Get_d();
      int* vtable =  *(int**)p;
      std::cout << "thread id " << omp_get_thread_num() << std::endl;
      std::cout << "Get_d() = " << p << " vtable = " << std::hex << vtable <<  std::endl;
      std::cout << "foo: " << p->foo() << std::endl;
    }
  }

private:
  static Derived _d;
#pragma omp threadprivate(_d)
};

Derived Container::_d;

int main() {
  Container cont;

#pragma omp parallel for
  for (int i = 0; i < omp_get_num_threads(); ++i)
    cont.print();

  return 0;
}

crashes when compiled as such:

icpc -v
icpc version 18.0.3 (gcc version 6.4.1 compatibility)
icpc -qopenmp -g -O0 crash.C -o crash

using Intel Compiler 2018 Update 3 (GCC 6.4 backend):

OMP_NUM_THREADS=2 ./crash

thread id 0
Get_d() = 0x603710 vtable = 0x6035a8
foo: 1
thread id 1
Get_d() = 0x14e4b1afbf00 vtable = 0
zsh: segmentation fault (core dumped)  OMP_NUM_THREADS=2 ./crash

The same code runs fine when compiled with -O2. The reason is that the threadprivate instance of _d on threads other than the main thread are not correctly initialized, the vtable ptr is 0x0 when compiled at -O0. This causes a crash when the program tries to add the offset of the virtual function foo to the start of the vtable, in order to invoke it. This is the corresponding piece of assembly:
 

(gdb) bt
#0  0x0000000000401966 in Container::print (this=0x7fffffffaea0) at crash.C:26
#1  0x00000000004014c2 in L_main_40__par_region0_2_2 () at crash.C:42
#2  0x00007ffff73c27d3 in __kmp_invoke_microtask () from /opt/intel/lib/libiomp5.so
#3  0x00007ffff738954a in ?? () from /opt/intel/lib/libiomp5.so
#4  0x00007ffff7388c0b in ?? () from /opt/intel/lib/libiomp5.so
#5  0x00007ffff73c2c30 in ?? () from /opt/intel/lib/libiomp5.so
#6  0x00007ffff6eb0075 in start_thread () from /usr/lib/libpthread.so.0
#7  0x00007ffff6be553f in clone () from /usr/lib/libc.so.6
(gdb) disassemble

...

  0x0000000000401957 <+371>:   mov    $0x0,%edx 
  0x000000000040195c <+376>:   movslq %edx,%rdx
  0x000000000040195f <+379>:   imul   $0x8,%rdx,%rdx (offset of function foo is stored in rdx)
  0x0000000000401963 <+383>:   add    (%rax),%rdx    (add vtable which is (%rax) to offset)
=> 0x0000000000401966 <+386>:   mov    (%rdx),%rax   (load (%rdx), causes segfault)


%rax contains the pointer to _d, (%rax) dereferences it in order to obtain the address of the vtable, $rdx is the offset of foo. Since (%rax) is 0 the last line is trying to access an invalid address which causes a segmentation violation.

0 Kudos
1 Reply
Viet_H_Intel
Moderator
93 Views

 

Thanks for reporting this problem. I have filed a bug CMPLRS-51113 to our developer.

Regards,

Viet

Reply