/**************** * Resize the array of A to NLIMBS. The additional space is cleared * (set to 0). */ void _gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs) { size_t i; if (nlimbs <= a->alloced) { /* We only need to clear the new space (this is a nop if the limb space is already of the correct size. */ for (i=a->nlimbs; i < a->alloced; i++) a->d[i] = 0; return; } /* Actually resize the limb space. */ if (a->d) { a->d = gcry_xrealloc (a->d, nlimbs * sizeof (mpi_limb_t)); for (i=a->alloced; i < nlimbs; i++) a->d[i] = 0; } else { if (a->flags & 1) /* Secure memory is wanted. */ a->d = gcry_xcalloc_secure (nlimbs , sizeof (mpi_limb_t)); else /* Standard memory. */ a->d = gcry_xcalloc (nlimbs , sizeof (mpi_limb_t)); } a->alloced = nlimbs; }
static void make_space ( struct make_space_ctx *c, size_t n ) { size_t used = c->pos - c->sexp->d; if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) { gcry_sexp_t newsexp; byte *newhead; c->allocated += 2*(n+sizeof(DATALEN)+1); newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 ); newhead = newsexp->d; c->pos = newhead + used; c->sexp = newsexp; } }
/**************** * Resize the array of A to NLIMBS. the additional space is cleared * (set to 0) [done by gcry_realloc()] */ void _gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs) { if (nlimbs <= a->alloced) return; /* no need to do it */ if (a->d) a->d = gcry_xrealloc (a->d, nlimbs * sizeof (mpi_limb_t)); else { if (a->flags & 1) /* Secure memory is wanted. */ a->d = gcry_xcalloc_secure (nlimbs , sizeof (mpi_limb_t)); else /* Standard memory. */ a->d = gcry_xcalloc (nlimbs , sizeof (mpi_limb_t)); } a->alloced = nlimbs; }
/* Fallback method using the registry to poll the statistics. */ static void registry_poll (void (*add)(const void*, size_t, enum random_origins), enum random_origins requester) { static int cbPerfData = PERFORMANCE_BUFFER_SIZE; int iterations; DWORD dwSize, status; PERF_DATA_BLOCK *pPerfData; /* Get information from the system performance counters. This can take a few seconds to do. In some environments the call to RegQueryValueEx() can produce an access violation at some random time in the future, in some cases adding a short delay after the following code block makes the problem go away. This problem is extremely difficult to reproduce, I haven't been able to get it to occur despite running it on a number of machines. MS knowledge base article Q178887 covers this type of problem, it's typically caused by an external driver or other program that adds its own values under the HKEY_PERFORMANCE_DATA key. The NT kernel, via Advapi32.dll, calls the required external module to map in the data inside an SEH try/except block, so problems in the module's collect function don't pop up until after it has finished, so the fault appears to occur in Advapi32.dll. There may be problems in the NT kernel as well though, a low-level memory checker indicated that ExpandEnvironmentStrings() in Kernel32.dll, called an interminable number of calls down inside RegQueryValueEx(), was overwriting memory (it wrote twice the allocated size of a buffer to a buffer allocated by the NT kernel). OTOH this could be coming from the external module calling back into the kernel, which eventually causes the problem described above. Possibly as an extension of the problem that the krnlWaitSemaphore() call above works around, running two instances of cryptlib (e.g. two applications that use it) under NT4 can result in one of them hanging in the RegQueryValueEx() call. This happens only under NT4 and is hard to reproduce in any consistent manner. One workaround that helps a bit is to read the registry as a remote (rather than local) registry, it's possible that the use of a network RPC call isolates the calling app from the problem in that whatever service handles the RPC is taking the hit and not affecting the calling app. Since this would require another round of extensive testing to verify and the NT native API call is working fine, we'll stick with the native API call for now. Some versions of NT4 had a problem where the amount of data returned was mis-reported and would never settle down, because of this the code below includes a safety-catch that bails out after 10 attempts have been made, this results in no data being returned but at does ensure that the thread will terminate. In addition to these problems the code in RegQueryValueEx() that estimates the amount of memory required to return the performance counter information isn't very accurate (it's much worse than the "slightly-inaccurate" level that the MS docs warn about, it's usually wildly off) since it always returns a worst-case estimate which is usually nowhere near the actual amount required. For example it may report that 128K of memory is required, but only return 64K of data. Even worse than the registry-based performance counters is the performance data helper (PDH) shim that tries to make the counters look like the old Win16 API (which is also used by Win95). Under NT this can consume tens of MB of memory and huge amounts of CPU time while it gathers its data, and even running once can still consume about 1/2MB of memory */ if (getenv ("GNUPG_RNDW32_NOPERF")) { static int shown; if (!shown) { shown = 1; log_info ("note: get performance data has been disabled\n"); } } else { pPerfData = gcry_xmalloc (cbPerfData); for (iterations=0; iterations < 10; iterations++) { dwSize = cbPerfData; if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, (LPBYTE) pPerfData, &dwSize); if (status == ERROR_SUCCESS) { if (!memcmp (pPerfData->Signature, L"PERF", 8)) (*add) ( pPerfData, dwSize, requester ); else log_debug ("rndw32: no PERF signature\n"); break; } else if (status == ERROR_MORE_DATA) { cbPerfData += PERFORMANCE_BUFFER_STEP; pPerfData = gcry_xrealloc (pPerfData, cbPerfData); } else { static int been_here; /* Silence the error message. In particular under Wine (as of 2008) we would get swamped with such diagnotiscs. One such diagnotiscs should be enough. */ if (been_here != status) { been_here = status; log_debug ("rndw32: get performance data problem: ec=%ld\n", status); } break; } } gcry_free (pPerfData); } /* Although this isn't documented in the Win32 API docs, it's necessary to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's implicitly opened on the first call to RegQueryValueEx()). If this isn't done then any system components which provide performance data can't be removed or changed while the handle remains active. */ RegCloseKey (HKEY_PERFORMANCE_DATA); }