eb34e6efd88628e68fd4bae305e1baacff26b91e galt Mon Mar 11 15:55:37 2013 -0700 Deal with out of memory issue in errAbort::getThreadVars() since errAbort thread data is being stored in a hash whose functions can themselves errAbort when out of memory. This issue was reported by Max H. and Mark D. diff --git src/lib/errabort.c src/lib/errabort.c index e3f8a7d..71889a3 100644 --- src/lib/errabort.c +++ src/lib/errabort.c @@ -283,44 +283,57 @@ } boolean isErrAbortInProgress() /* Flag to indicate that an error abort is in progress. * Needed so that a warn handler can tell if it's really * being called because of a warning or an error. */ { struct perThreadAbortVars *ptav = getThreadVars(); return ptav->errAbortInProgress; } static struct perThreadAbortVars *getThreadVars() /* Return a pointer to the perThreadAbortVars for the current pthread. */ { +pthread_t pid = pthread_self(); // can be a pointer or a number +// Don't safef, theoretically that could abort. +char pidStr[64]; +snprintf(pidStr, sizeof(pidStr), "%lld", ptrToLL(pid)); +pidStr[ArraySize(pidStr)-1] = '\0'; + +static char pidInUse[64] = ""; // use a string since there is no known unused value for pthread_t variable +if (sameString(pidStr, pidInUse)) // avoid deadlock on self + { // this only happens when it has aborted already due to out of memory + // which should be a rare occurrence. + char *errMsg = "errAbort re-entered due to out-of-memory condition. Exiting."; + write(STDERR_FILENO, errMsg, strlen(errMsg)); + exit(1); + } + static pthread_mutex_t ptavMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock( &ptavMutex ); +snprintf(pidInUse, sizeof(pidInUse), "%lld", ptrToLL(pid)); +pidInUse[ArraySize(pidInUse)-1] = '\0'; + static struct hash *perThreadVars = NULL; -pthread_t pid = pthread_self(); // can be a pointer or a number -// A true integer has function would be nicer, but this will do. -// Don't safef, theoretically that could abort. -char key[64]; -snprintf(key, sizeof(key), "%lld", ptrToLL(pid)); -key[ArraySize(key)-1] = '\0'; if (perThreadVars == NULL) perThreadVars = hashNew(0); -struct hashEl *hel = hashLookup(perThreadVars, key); +struct hashEl *hel = hashLookup(perThreadVars, pidStr); if (hel == NULL) { // if it is the first time, initialization the perThreadAbortVars struct perThreadAbortVars *ptav; AllocVar(ptav); ptav->debugPushPopErr = FALSE; ptav->errAbortInProgress = FALSE; ptav->warnIx = 0; ptav->warnArray[0] = defaultVaWarn; ptav->abortIx = 0; ptav->abortArray[0] = defaultAbort; - hel = hashAdd(perThreadVars, key, ptav); + hel = hashAdd(perThreadVars, pidStr, ptav); } +pidInUse[0] = '\0'; pthread_mutex_unlock( &ptavMutex ); return (struct perThreadAbortVars *)(hel->val); }