4

I have a perfectly working program which connects to a video camera (an IDS uEye camera) and continuously grabs frames from it and displays them.

However, when loading a specific dll before connecting to the camera, the program runs with 100% CPU load. If I load the dll after connecting to the camera, the program runs fine.

int main()
{
    INT nRet = IS_NO_SUCCESS;
    // init camera (open next available camera)
    m_hCam = (HIDS)0;

    // (A) Uncomment this for 100% CPU load:
    // HMODULE handle = LoadLibrary(L"myInnocentDll.dll");

    // This is the call to the 3rdparty camera vendor's library:
    nRet = is_InitCamera(&m_hCam, 0);    

    // (B) Uncomment this instead of (A) and the CPU load won't change
    // HMODULE handle = LoadLibrary(L"myInnocentDll.dll");

    if (nRet == IS_SUCCESS)
    {
        /*
         * Please note: I have removed all lines which are not necessary for the exploit.
         * Therefore this is NOT a full example of how to properly initialize an IDS camera!
         */
        is_GetSensorInfo(m_hCam, &m_sInfo);

        GetMaxImageSize(m_hCam, &m_s32ImageWidth, &m_s32ImageHeight);

        m_nColorMode = IS_CM_BGR8_PACKED;// IS_CM_BGRA8_PACKED;
        m_nBitsPerPixel = 24; // 32;
        nRet |= is_SetColorMode(m_hCam, m_nColorMode);

        // allocate image memory.
        if (is_AllocImageMem(m_hCam, m_s32ImageWidth, m_s32ImageHeight, m_nBitsPerPixel, &m_pcImageMemory, &m_lMemoryId) != IS_SUCCESS)
        {
            return 1;
        }
        else
        {
            is_SetImageMem(m_hCam, m_pcImageMemory, m_lMemoryId);
        }
    }
    else
    {
        return 1;
    }

    std::thread([&]() {
        while (true) {
            is_FreezeVideo(m_hCam, IS_WAIT);
            /*
             * Usually, the image memory would now be grabbed via is_GetImageMem().
             * but as it is not needed for the exploit, I removed it as well
             */
        }
        }).detach();

    cv::waitKey(0);
}

Independently of the actually used camera driver, in what way could loading a dll change the performance of it, occupying 100% of all available CPU cores? When using the Visual Studio Diagnostic Tools, the excess CPU time is attributed to "[External Call] SwitchToThread" and not to the myInnocentDll.

Loading just the dll without the camera initialization does not result in 100% CPU load.

I was first thinking of some static initializers in the myInnocentDll.dll configuring some threading behavior, but I did not find anything pointing in this direction. For which aspects should I look for in the code of myInnocentDll.dll?

PhilLab
  • 4,777
  • 1
  • 25
  • 77
  • 3
    The 100% cpu being used by `SwitchToThread` is most likely coming from a spinlock. Are you doing anything in your `DllMain` for thread/process attach events? [Here are some things that will cause problems](https://devblogs.microsoft.com/oldnewthing/20140821-00/?p=183). Static initializations could also invoke the same. If nothing, I'd bite the bullet and just break into the process when it's in `SwitchToThread` and step out to find what's doing it. You'll have to debug in assembly but it's not terribly difficult to get a picture of what's going on. – TainToTain Aug 03 '20 at 20:04
  • @TainToTain Thanks for taking a look! DllMain is not present in my code. It could be some static initializations indeed, however I am clueless on how to find the needle here. Unfortunately, in Release Mode, attaching to the stack just reveals "External code". And in debug mode, the problem does not appear – PhilLab Aug 04 '20 at 16:19
  • `myInnocentDll.dll` will have a `DllMain`. What code is in that function? – 1201ProgramAlarm Aug 04 '20 at 16:36
  • Some other things to check in `myInnocentDll`: are you using COM?; do any of the ctors of statically initialized objects call into STL or CRT methods? Basically anything that might load another library in a static initializer is bad and can cause a deadlock. I suspect there will be. For Visual Studio assembly-level debugging, you need to [enable "address-level debugging"](https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-use-the-disassembly-window?view=vs-2019#:~:text=To%20enable%20the%20Disassembly%20window,select%20Enable%20address%2Dlevel%20debugging.) – TainToTain Aug 04 '20 at 18:46
  • Can you use Process Explorer and inspect the thread stacks and what they do with the CPU time? https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer – chakaz Aug 05 '20 at 18:20
  • Attempted threading in any static initializer in `myInnocentDll.dll` is just as likely. Another likely option is to check the vendor libraries behavior with Intel Inspector for race conditions. Last, use Dependency Walker to check which symbols and other libraries your, and the vendors library each pull in, you may encounter a conflict there! – Ext3h Aug 07 '20 at 05:01
  • At least in the code files there is no DllMain to be found, maybe it is generated by cmake or the msvc automatically? Unfortunately, the myInnocentDll is rather large but I will look out for COM and threading during static init. Thanks for all the hints and debugging tips! – PhilLab Aug 10 '20 at 06:50

2 Answers2

0

After a lot of digging I found the answer and it is both frustratingly simple and frustrating by itself:

It is Microsoft's poor support of OpenMP. When I disabled OpenMP in my project, the camera driver runs just fine.

The reason seems to be that the Microsoft compiler uses OpenMP with busy waiting and there is also the possibility to manually configure OMP_WAIT_POLICY, but as I was not depending on OpenMP anyways, disabling was the easiest solution for me.

I still don't understand why the CPU only went up high when using the camera and not when running the rest of my solution, even though the camera library is pre-built and my disabling/enabling of OpenMP compilation cannot have any effect on it. And I also don't understand why they bothered to make a hotfix for VS2010 but have no real fix as of VS2019, which I am using. But the problem is averted.

PhilLab
  • 4,777
  • 1
  • 25
  • 77
0

You can disable CPU idle state in the IDS camera manager and then the minimum CPU load in the windows energy plans is set to 100%

I think this is worth mentioning here, even you solved your problem already.

drewsed
  • 1
  • 1