?
Solved

OUT OF PRIVATE HANDLES

Posted on 2004-11-12
13
Medium Priority
?
1,063 Views
Last Modified: 2008-01-09
i'm not very good on c++ and i got to develop a dll for our lotus domino server.
the problem i have is, when the dll is called about 1000 times the http-task of the domino server crashes whith following error message on the server console:
"MemAlloc: OUT OF PRIVATE HANDLES! -- pid 000004F4 Handles used so far 16953, Maximum handles = 10495"

here's the code of my dll
i think that my mistake is, that i use goto's when an error appears and i don't free the memory.

------------------------------------------------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>

// Lotus C API for Domino and Notes Header files.
#include <global.h>
#include <editods.h>
#include <osmem.h>
#include <schgtw.h>
#include <textlist.h>
#include <lapiplat.h>

// Header file.
#include "busytime2.h"
   

/************************************************************************
    DLL Main
*************************************************************************/
BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved){
    switch (ul_reason_for_call){
            case DLL_PROCESS_ATTACH:
            case DLL_THREAD_ATTACH:
            case DLL_THREAD_DETACH:
            case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}


/*************************************************************************
      Initializing Notes
*************************************************************************/
BUSYTIME_DLL_API int Start_Notes (char *exepath, char *inipath) {            
      STATUS sError;
      char *argv[2];
      //Umschlüsseln der Parameter
      argv[0] = exepath;
      argv[1] = inipath;
      //Notesinitialisierung
    sError = NotesInitExtended(2, argv);
      // Errorhandling
    if (sError != NOERROR) {
        LAPI_RETURN(2);
      } else {
        LAPI_RETURN(0);
      }
}


/*************************************************************************
      Wrapper function to exit from Domino and Notes.
*************************************************************************/


BUSYTIME_DLL_API void Stop_Notes (void) {
    NotesTerm();
}


/*************************************************************************
      Write Busytimes to File
*************************************************************************/
BUSYTIME_DLL_API int BusyTimeToFile (char *szUser, char *startTime, char *endTime, char *fname) {
      //Declarations
      char                  *theSchedList;
      int                        retcode=0;
      int                        laenge=0;
      int                        i;
      int                        anzuser=0;
      int                        anzschedules=0;
      char                  szMyUser[256]="";
      char                  *tmpUser=szUser;
      char                  *tmpStartTime;
      char                  *tmpEndTime;
      int                        zaehler=0;
      //Filepointers
      FILE                  *fz;
      //
      VOID                  *list_ptr;
      WORD                  list_size;
      DWORD                  retdwSize;
      //Notestypes
      STATUS                  sError = NOERROR;                  //typedef WORD STATUS;
      UNID                  apptUnid;                              //#define UNID UNIVERSALNOTEID
      HCNTNR                  schListCntnr = NULLHANDLE;      //typedef HANDLE HCNTNR; [ void LNPUBLIC SchContainer_Free(HCNTNR  hCntnr); ]
      HCNTNROBJ            schedObj;                              //typedef DWORD HCNTNROBJ;
      HCNTNROBJ            nextSchedObj;
      HCNTNROBJ            hMoreObj = NULLCNTNROBJ;
      TIMEDATE_PAIR      interval;                              //typedef struct {TIMEDATE Lower;TIMEDATE Upper;} TIMEDATE_PAIR;
      TIMEDATE_PAIR      pInterval;
      SCHEDULE            *nextSchedule;                        //typedef struct {DWORD reserved[8]; DBID dbReplicaID; TIMEDATE_PAIR Interval; DWORD dwErrGateway; STATUS error; WORD wReserved; WORD wOwnerNameSize; } SCHEDULE;
      SCHEDULE            *pSchedule;
      HANDLE                  list_handle;                        //typedef unsigned int HANDLE; [ OSMemAlloc / OSMemFree ]
      HANDLE                  rethSchedList;

      //try to open file
      if ((fz=fopen(fname,"w"))==NULL) {
            retcode=1;
            goto done;
      } else {
            sError = ListAllocate (0, 0, FALSE, &list_handle, &list_ptr, &list_size);
            if (sError != NOERROR)
                  goto NError;
            i=0;
            while (*tmpUser!='\0') {
                  if (i>=256) {
                        retcode=2;
                        goto done;
                  }
                  if(*tmpUser!=',') {
                        szMyUser[i++]=*tmpUser;
                  } else {
                        szMyUser[i++]='\0';
                        anzuser++;
                        sError = ListAddEntry(list_handle, FALSE, &list_size, (WORD) anzuser, szMyUser, (WORD) strlen(szMyUser));
                        if (sError != NOERROR)
                              goto NError;
                        i=0;
                  }
                  tmpUser++;
            }
            //add last user
            szMyUser[i]='\0';
            anzuser++;
            sError = ListAddEntry(list_handle, FALSE, &list_size, (WORD) anzuser, szMyUser, (WORD) strlen(szMyUser));
            if (sError != NOERROR)
                  goto NError;

            //Convert Start and Endtime to Notesdatetime
            tmpStartTime = startTime;
            tmpEndTime       = endTime;
            sError = ConvertTextToTIMEDATE(NULL, NULL, &tmpStartTime, (WORD) strlen(startTime), &interval.Lower);
            if (sError != NOERROR)
                  goto NError;
            sError = ConvertTextToTIMEDATE(NULL, NULL, &tmpEndTime, (WORD) strlen(endTime), &interval.Upper);
            if (sError != NOERROR)
                  goto NError;
            //Get Schedules
            OSUnlockObject(list_handle);
            list_ptr = OSLockObject(list_handle);
            sError = SchRetrieve(&apptUnid, NULL, SCHRQST_FORCEREMOTE|SCHRQST_EACHPERSON,&interval,(LIST *)list_ptr, &schListCntnr, NULL, NULL, NULL);  
            if (sError != NOERROR)
                  goto NError;
            
            // going through the schedules
            while (sError == NOERROR) {
                  zaehler++;
                  //beginn
                  if (anzschedules==0) {
                        // first schedule
                        sError = SchContainer_GetFirstSchedule(schListCntnr, &schedObj, &pSchedule);          
                        if (sError != NOERROR)
                              goto NError;
                        memcpy (szMyUser,pSchedule + 1 ,pSchedule->wOwnerNameSize);
                  }else {
                        // next schedule
                        sError = SchContainer_GetNextSchedule(schListCntnr, schedObj, &nextSchedObj, &nextSchedule);
                        if (sError != NOERROR)
                              goto NError;
                        schedObj=nextSchedObj;
                        memcpy (szMyUser,nextSchedule + 1 ,nextSchedule->wOwnerNameSize);
                  }
                  
                  //* extract the list
                  sError = Schedule_ExtractSchedList(      schListCntnr, schedObj, &pInterval, (unsigned long *) &retdwSize, &rethSchedList, &hMoreObj);
                  if (sError == NOERROR) {
                        anzschedules++;
                        fprintf(fz,"#\n");
                        fprintf(fz,"%s\n",szMyUser);
                        theSchedList=(char *)OSLockObject(rethSchedList);
                        // ... und in ein Stringarray hinzufügen
                        DumpTextSchedEntryListToFile(theSchedList,fz);
                        OSUnlockObject(rethSchedList);  
                  } else if (sError==1002 && zaehler<anzuser) {
                        sError=NO_ERROR;
                  }else {
                        goto NError;
                  }
            }

            //* Free all handles
            
            //OSUnlockObject(theSchedList);
            //OSMemFree(theSchedList);

            OSUnlockObject(list_handle);
            OSMemFree(list_handle);

            OSUnlockObject(rethSchedList);
            OSMemFree(rethSchedList);
      
            Schedule_Free(schListCntnr,schedObj);
            SchContainer_Free(schListCntnr);
      }
      
NError:
      retcode=0;
      if (sError!=NO_ERROR && sError!=1006 && sError!=1002) {
            retcode=2;
      } else if (anzuser!=anzschedules) {
            retcode=1;
      }
done:
      fclose(fz);
      LAPI_RETURN(retcode);
}

/************************************************************************
    FUNCTION:     DumpTextSchedEntryListToFile
*************************************************************************/
void LNPUBLIC DumpTextSchedEntryListToFile(char *pSchedList, FILE *fz) {
      //Declaration
      int                        num=0;
      int                        i=0;
      char                  szLowerTD[MAXALPHATIMEDATE+1];
      char                  szUpperTD[MAXALPHATIMEDATE+1];
      //Notesdatatypes
      SCHED_LIST            SchedList;            //typedef struct { DWORD NumEntries; WORD  wApplicationID; WORD Spare; } SCHED_LIST;
      SCHED_ENTRY            SchedEntry;            //typedef struct { UNID Unid; TIMEDATE_PAIR Interval; BYTE Attr; BYTE UserAttr; BYTE spare[2];} SCHED_ENTRY;

      
      memcpy( (char*)&SchedList, pSchedList, sizeof(SCHED_LIST) );
      pSchedList += sizeof(SCHED_LIST);
      num = SchedList.NumEntries;
      //fprintf(fz,"next\n");
      for (i=0;i<num;i++) {
            memcpy((char *)&SchedEntry, pSchedList, sizeof(SCHED_ENTRY) );
            //Check if busy
            if (SCHED_ATTR_AVAILABLE(SchedEntry.Attr)==FALSE) {
                  GetTDString( &(SchedEntry).Interval.Lower, szLowerTD );
                  GetTDString( &(SchedEntry).Interval.Upper, szUpperTD );
                  fprintf(fz,"%s-%s\n",szLowerTD,szUpperTD);
            }
            pSchedList += sizeof(SCHED_ENTRY);
      }

}

/************************************************************************
    FUNCTION:   GetTDString
*************************************************************************/
void LNPUBLIC GetTDString( TIMEDATE * ptdModified, char * szTimedate )
{
    WORD  wLen;
    ConvertTIMEDATEToText( NULL, NULL, ptdModified, szTimedate, MAXALPHATIMEDATE, &wLen );
    szTimedate[wLen] = '\0';
    return;
}
------------------------------------------------------------------------------------------------------------------
0
Comment
Question by:ragerino
10 Comments
 
LVL 30

Accepted Solution

by:
Axter earned 500 total points
ID: 12564645
You should avoid using goto.  It will give you much more problems then it solves.


 if ((fz=fopen(fname,"w"))==NULL) {
          retcode=1;
          goto done;
     }

The above section of the code tries to open a file, and thens jumps to done if it fails.
Done tries to close this same file that could not be open.
0
 
LVL 13

Expert Comment

by:SteH
ID: 12564651
Can you show how you typically call the DLL? And can some of the initialisation be done in the call of
BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
taking care of the ul_reason_for_call parameter?

          case DLL_PROCESS_ATTACH: // a new process (application) calls DLL
          case DLL_THREAD_ATTACH:   // a new thread (of a known process) calls DLL
          case DLL_THREAD_DETACH:  
          case DLL_PROCESS_DETACH:

0
 
LVL 30

Expert Comment

by:Axter
ID: 12564655
The main problem I see, is that after you successfully open the file, you then jump to NError.
NError does not close the file before exiting, which means you end up with a bunch of open files, and you run out of file handles.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 30

Expert Comment

by:Axter
ID: 12564668
Disregard my last comment.
I didn't see that NError flows down to done.

0
 
LVL 13

Expert Comment

by:SteH
ID: 12564675
if ((fz=fopen(fname,"w"))==NULL) {
          retcode=1;
          goto done;
     }
//snip
done:
     fclose(fz);
     LAPI_RETURN(retcode);
}
could be replaced with

f ((fz=fopen(fname,"w"))==NULL) {
          retcode=1;
          LAPI_RETURN(retcode);
     }
//snip
0
 
LVL 13

Assisted Solution

by:SteH
SteH earned 500 total points
ID: 12564699
But NError does not call the OSMemFree () and that can be the problem. Since the things to free depends on where you branch to NError I think you can equally save put the code for returning from the function several times in that function. And at each place you close and free what is open.

Else you need to adopt exception handling: When some error occurs cleanup is still done. But this will be a major rewrite, so perhaps not a real option.
0
 
LVL 22

Assisted Solution

by:grg99
grg99 earned 500 total points
ID: 12564738
One way to ensure things get cleaned up is to have a policy of returning ONLY from the very bottom of the routine, and have cleanup code just before the return.   Or to use structured exception handling, which amounts to much the same thing.

0
 
LVL 3

Author Comment

by:ragerino
ID: 12564963
is there a tool which watches the busytime2.dll and tells me how much memory is still locked after it finished ????
0
 
LVL 14

Assisted Solution

by:wayside
wayside earned 500 total points
ID: 12565009
Make sure you initialize all your handles to NULL:

HANDLE               list_handle = NULL;

Add code to close the handles after the done: label, and check them first:

done:
          //* Free all handles
         
          if (list_handle) {
            OSUnlockObject(list_handle);
            OSMemFree(list_handle);
          }

          if (rethSchedList) {
             OSUnlockObject(rethSchedList);
             OSMemFree(rethSchedList);
          }

etc.

You could still be leaking from within the while loop, it's hard to tell.
0
 
LVL 13

Expert Comment

by:SteH
ID: 12565014
Since the memory is usually not allocated in the frame of the DLL but in the frame of the calling application it has to be done within all those applications.

Have a look at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/_core_detecting_memory_leaks.asp
for several ways of debugging memory allocations. Difficulty is that memory, GDI resource and kernel objects are all handled differently and thus need different approaches for debugging.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
Suggested Courses

839 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