Solved

Unhandled error when exiting an DLL which grabs data from a database and store data into an array of structure

Posted on 2004-09-28
8
1,525 Views
Last Modified: 2008-01-09
Hi,

Here's what I did.
I declared a structure for holding data:

#define LEN_DATA 100

struct DB_DATA
{
      char m_Username[LEN_DATA];
      char m_Password[LEN_DATA];
      char m_Submit[LEN_DATA];
};

DB_DATA* p_DBData = new DB_DATA;

Then I have 2 DLL functions for constructing and destroying the array:

BOOL EXPORTED_DLL_FUNCTION ConstructUserArray()
{

(codes ommited for database connection.. )

      SDWORD cb;
      char szUsername[LEN_DATA];
      char szPassword[LEN_DATA];
      char szSubmit[LEN_DATA];

      SQLBindCol(h_stmt, 1, SQL_C_CHAR, szUsername, LEN_DATA, &cb);
      SQLBindCol(h_stmt, 2, SQL_C_CHAR, szPassword, LEN_DATA, &cb);
      SQLBindCol(h_stmt, 3, SQL_C_CHAR, szSubmit, LEN_DATA, &cb);

      rc = SQLFetch(h_stmt);

      m_NumRecord = 0;

      while (SQL_SUCCESS == rc)
      {
            strcpy(p_DBData[m_NumRecord].m_Username, szUsername);
            strcpy(p_DBData[m_NumRecord].m_Password, szPassword);
            strcpy(p_DBData[m_NumRecord].m_Submit, szSubmit);
            m_NumRecord++;

            rc = SQLFetch(h_stmt);
      }

(codes ommited for database disconnection.. )
}

BOOL EXPORTED_DLL_FUNCTION DestroyUserArray()
{
      for (int i=0; i<sizeof(p_DBData); i++){
            p_DBData[i].m_Username[0] = 0;
            p_DBData[i].m_Password[0] = 0;
            p_DBData[i].m_Submit[0] = 0;
      }
      return true;
}

The error was generated when I was exiting the DLL.. here's what I saw from the Call Stack:

>      mfc71d.dll!CThreadSlotData::GetThreadValue(int nSlot=2012648534)  Line 269      C++

with the code:
inline void* CThreadSlotData::GetThreadValue(int nSlot)
{
      EnterCriticalSection(&m_sect);
      ASSERT(nSlot != 0 && nSlot < m_nMax);
      ASSERT(m_pSlotData != NULL);
      ASSERT(m_pSlotData[nSlot].dwFlags & SLOT_USED);
      ASSERT(m_tlsIndex != (DWORD)-1);
      if( nSlot <= 0 || nSlot >= m_nMax ) // check for retail builds.
      {
            LeaveCriticalSection(&m_sect);
            return NULL;
      }

      CThreadData* pData = (CThreadData*)TlsGetValue(m_tlsIndex);
      if (pData == NULL || nSlot >= pData->nCount)
      {
            LeaveCriticalSection(&m_sect);
            return NULL;
      }
      void* pRetVal = pData->pData[nSlot];
      LeaveCriticalSection(&m_sect);
      return pRetVal;      <------------------------------------------- Line 269
}

I tried to free the variables szUsername, szPassword, szSubmit right after the while loop but then it generates the error at the end of the free() function..

Any help is greatly appreciated..

Thanks a lot.
0
Comment
Question by:ewong_111
  • 4
  • 3
8 Comments
 
LVL 16

Expert Comment

by:nonubik
ID: 12172421
>I tried to free the variables szUsername, szPassword, szSubmit right after the while loop but then it generates the error at the end of the free() function..

There is no need for that, they are staticaly allocated, so you don't need to free them.

As for your problem, try to pass the void * as parameter, not to return it:

inline void CThreadSlotData::GetThreadValue(int nSlot, void *pRetVal)
{
...
   pRetVal = pData->pData[nSlot];
    LeaveCriticalSection(&m_sect);

}
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 12172483
>>mfc71d.dll!CThreadSlotData::GetThreadValue(int nSlot=2012648534)

Isn't 2012648534 a quite huge value? BTW, when exactly is that function being called? The TLS slot might be gone once the thread detaches.

0
 
LVL 2

Author Comment

by:ewong_111
ID: 12172561
nonubik,

The point is, the CThreadSlotData::GetThreadValue function is in the mfc71d.dll (I assumed) that I am checking the Call stack and see that it hangs there, not that I wrote the function myself and have a control of what to do with it or what valuable I can pass to it.
As I said, my program used an DLL and it works just fine before I exit it. I used a dialog based program to access the DLL and the error was generated when I click on "Cancel" which is to exit the DLL.

ewong_111
0
 
LVL 2

Author Comment

by:ewong_111
ID: 12172604
jkr,

The DLL has another function which set up a hook for monitoring keystrokes and mouse actions.
I am not sure when the CThreadSlotData::GetThreadValue is called, but I "feel" like it is somewhere when my DLL Client program (dialog based) is terminating the DLL.
In addition, the array of structure is used to compare the keystokes with the values in the database.. not sure if this help..
Thanks a lot.

ewong_111
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 2

Author Comment

by:ewong_111
ID: 12172899
Hi,

I tried to change the functions to virtual functions:

class KeyApp : public CWinApp
{
public:
      KeyApp();

// Overrides
public:
      virtual BOOL InitInstance();
      virtual BOOL ExitInstance();
      virtual BOOL ConstructUserArray();
      virtual BOOL DestroyUserArray();

      DECLARE_MESSAGE_MAP()
};

and called the ConstructUserArray() in InitInstance():

BOOL CKeyApp::InitInstance()
{
      ConstructUserArray();
      AFX_MANAGE_STATE(AfxGetStaticModuleState());
      g_hInstance = AfxGetInstanceHandle();
      return TRUE;
}

and the DestroyUserArrar() in ExitInstance():

int CGCRCoKeyApp::ExitInstance()
{
      ExitHook();
      DestroyUserArray();
      return CWinApp::ExitInstance();
}

and now I get the error code in the free() function:
>      msvcr71.dll!free(void * pBlock=0x003745e8)  Line 103      C

#ifdef _MT
            }
            __finally {
                _munlock(_HEAP_LOCK );
            }
#endif  /* _MT */

            if (pmap == NULL)
                HeapFree(_crtheap, 0, pBlock);
        }
#endif  /* CRTDLL */
        else    //  __active_heap == __SYSTEM_HEAP
#endif  /* _WIN64 */
        {
            HeapFree(_crtheap, 0, pBlock);
        }
} <------------------------------------------------ Line 103

jkr, I think your direction is correct, somehow the TLS slot was gone before the thread detaches.. but what did I do to cause that happen?

Thanks a lot..

ewong_111
0
 
LVL 86

Expert Comment

by:jkr
ID: 12172919
Do you have a 'DllMain()' where you can monitor DLL_THREAD_DETACH? That's the time to discard the slot.
0
 
LVL 2

Author Comment

by:ewong_111
ID: 12172986
jkr,

no, I don't have a DllMain(), but I guess it's time for me to build it.. would you please give me a little hint on what to do to discard the slot in there?
Thank you so much.

ewong_111
0
 
LVL 86

Expert Comment

by:jkr
ID: 12173168
I don't know the class you are using, but it'd be something like

// DllMain() is the entry-point function for this DLL.
BOOL
WINAPI
DllMain ( HINSTANCE, DWORD dwReason, LPVOID lpvReserved) {


    switch ( dwReason) {
 
        // The DLL is loading due to process
        // initialization or a call to LoadLibrary.
 
        case DLL_PROCESS_ATTACH:

            // Allocate a TLS index.
 
            if ( 0xFFFFFFFF == ( dwTlsIndex = TlsAlloc ())) {

                return FALSE;
            }

        // No break: Initialize the index for first thread.
 
        // The attached process creates a new thread.
 
        case DLL_THREAD_ATTACH:
 
            // Initialize the TLS index for this thread.
 
            TlsSetValue ( dwTlsIndex, <some pointer value>);
            break;
 
        // The thread of the attached process terminates.
 
        case DLL_THREAD_DETACH:
 
            TlsSetValue ( dwTlsIndex, NULL);
            break;
 
        // DLL unload due to process termination or FreeLibrary.
 
        case DLL_PROCESS_DETACH:

            TlsFree ( dwTlsIndex);
            break;
 
        default:
            break;
    }
 
    return TRUE;
}
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now