IBM Support

LI78255: DYNAMIC_CAST NOT RETURNING THE CORRECT POINTER

Subscribe

You can track all active APARs for this component.

 

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:

    PI15855

  • 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