Fixes are available
APAR status
Closed as program error.
Error description
Applications that perform concurrent dynamic_cast in a multi-threaded environment may receive an incorrect return value from the dynamic_cast function. Below is a test program that demonstrates dynamic_cast returning an incorrect pointer value. #define CAST_SUCCESSFUL_OUTPUT 0 #define NUM_THREADS 60 #define FORCE_BAD_CAST 0 class A { public: // Since RTTI is included in the virtual method table there should be at least one virtual function. virtual ~A() { }; virtual void methodSpecificToInstance() = 0 ; }; class B : public A { public: void methodSpecificToInstance() { std::cout << "Method specific for B was invoked" << std::endl; }; ~B() { }; }; class C : public A { public: void methodSpecificToInstance() { std::cout << "Method specific for C was invoked" << std::endl; }; ~C() { }; }; class D : public A { public: void methodSpecificToInstance() { std::cout << "Method specific for D was invoked" << std::endl; }; ~D() { }; }; class E : public A { public: void methodSpecificToInstance() { std::cout << "Method specific for E was invoked" << std::endl; }; ~E() { }; }; class F : public A { public: void methodSpecificToInstance() { std::cout << "Method specific for F was invoked" << std::endl; }; ~F() { }; }; typedef std::vector<A*> ObjectVector; bool iKeepRunning = true; int threadNumber = 0; void* runCasts(void* = 0) { int thdNum = threadNumber; threadNumber++; int count = 0; ObjectVector myObjects; myObjects.resize(6); myObjects[0] = NULL; myObjects[1] = new B(); myObjects[2] = new C(); myObjects[3] = new D(); myObjects[4] = new E(); myObjects[5] = new F(); typedef std::tr1::mt19937 Engine_19937; Engine_19937 engine; engine.seed(time(NULL)); std::tr1::uniform_int<int> distribution(1,5); Engine_19937 engineSleep; engineSleep.seed(time(NULL)); std::tr1::uniform_int<int> distributionSleep(0,2); while (iKeepRunning && count != -1) { int index = distribution(engine); int sleepTime = distributionSleep(engineSleep); usleep(sleepTime*100); A* beforePtr = myObjects[index]; if (count %10000000 == 0) { std::cout << thdNum << ":" << sleepTime << ":" << count << ":" << index << std::endl; } if (index == 1) { if (FORCE_BAD_CAST) { if (count %10000003 == 1 ) { beforePtr = myObjects[3]; } } B* afterPtr = dynamic_cast<B*>(beforePtr); if (afterPtr == NULL) { std::cerr << "Cast failed - type A" << std::endl; } else if (beforePtr != afterPtr) { std::cerr << "Pointers differ after cast - type B" << std::endl; } else { if ( CAST_SUCCESSFUL_OUTPUT ) { std::cerr << "Successful cast - type B" << std::endl; } } } else if (index == 2) { C* afterPtr = dynamic_cast<C*>(beforePtr); if (afterPtr == NULL) { std::cerr << "Cast failed - type C" << std::endl; } else if (beforePtr != afterPtr) { std::cerr << "Pointers differ after cast - type C" << std::endl; } } else if (index == 3) { D* afterPtr = dynamic_cast<D*>(beforePtr); if (afterPtr == NULL) { std::cerr << "Cast failed - type D" << std::endl; } else if (beforePtr != afterPtr) { std::cerr << "Pointers differ after cast - type D" << std::endl; } } else if (index == 4) { E* afterPtr = dynamic_cast<E*>(beforePtr); if (afterPtr == NULL) { std::cerr << "Cast failed - type E" << std::endl; } else if (beforePtr != afterPtr) { std::cerr << "Pointers differ after cast - type E" << std::endl; } } else if (index == 5) { F* afterPtr = dynamic_cast<F*>(beforePtr); if (afterPtr == NULL) { std::cerr << "Cast failed - type F" << std::endl; } else if (beforePtr != afterPtr) { std::cerr << "Pointers differ after cast - type F" << std::endl; } } else { std::cerr << "Unknown index: " << index << std::endl; } count++; } } int main() { pthread_t thread_array[NUM_THREADS]; for (int i = 0 ; i < NUM_THREADS ; i++) { sleep(1); std::cout << "Starting thread " << i << std::endl; pthread_create(&thread_array[i], NULL, &runCasts, NULL); } runCasts(); sleep(10); iKeepRunning = false; } ===== ACTUAL OUTPUT: $./testProg Starting thread 0 0:2:0:4 . . Starting thread 59 59:2:0:5 60:2:0:5 Pointers differ after cast - type E ===== EXPECTED OUTPUT: There should be no "Pointers differ after cast" in the output.
Local fix
N/A
Problem summary
**************************************************************** * USERS AFFECTED: Multithreaded applications that run on z/OS * * V2R1 with LP64 and that use dynamic_cast * * function can be affected by this issue. * **************************************************************** * PROBLEM DESCRIPTION: There was a section in the C++ runtime * * (within dynamic_cast) where a lock for * * the return value of the dynamic_cast * * pointer was released and the * * dynamic_cast pointer was returned. But * * between the release of the lock and * * the return of the dynamic_cast * * pointer, there was a chance that * * another thread could change the return * * value of the dynamic_cast pointer. As * * a result, there was a small window for * * a race condition. * **************************************************************** * RECOMMENDATION: * ****************************************************************
Problem conclusion
Applied provided service.
Temporary fix
Comments
APAR Information
APAR number
LI78255
Reported component name
XL C/C++ FOR LI
Reported component ID
5725C7300
Reported release
D10
Status
CLOSED PER
PE
NoPE
HIPER
NoHIPER
Special Attention
NoSpecatt
Submitted date
2014-10-30
Closed date
2014-10-30
Last modified date
2014-10-30
APAR is sysrouted FROM one or more of the following:
APAR is sysrouted TO one or more of the following:
Modules/Macros
CELHDCTI CELQDCTI CEL4DCTI
Fix information
Fixed component name
XL C/C++ FOR LI
Fixed component ID
5725C7300
Applicable component levels
RD10 PSY
[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SSXVZZ","label":"XL C\/C++ for Linux"},"Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"13.1","Line of Business":{"code":"LOB57","label":"Power"}}]
Document Information
Modified date:
17 October 2021