fix image cache summary information to properly use a format string

remove snprintf buffer overflow possibility
fix the about:imagecache fetcher to contain the output formatting and use summary information formatting

svn path=/trunk/netsurf/; revision=13039
This commit is contained in:
Vincent Sanders 2011-10-12 12:34:11 +00:00
parent 1badc58b83
commit eb9c223f9d
3 changed files with 225 additions and 132 deletions

View File

@ -198,7 +198,21 @@ static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
goto fetch_about_imagecache_handler_aborted;
/* image cache summary */
slen = image_cache_snsummaryf(buffer, sizeof(buffer), NULL);
slen = image_cache_snsummaryf(buffer, sizeof(buffer),
"<p>Configured limit of %a hysteresis of %b"
"<p>Total bitmap size in use %c (in %d)"
"<p>Age %es"
"<p>Peak size %f (in %g)"
"<p>Peak image count %h (size %i)"
"<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
"(%pj%%/%pk%%/%pl%%/%pm%%)"
"<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
"(%pn%%/%po%%/%pq%%/%pr%%)"
"<p>Total images never rendered: %s "
"(includes %t that were converted)"
"<p>Total number of excessive conversions: %u "
"(from %v images converted more than once)"
"<p>Bitmap of size %w had most (%x) conversions");
if (slen >= (int) (sizeof(buffer)))
goto fetch_about_imagecache_handler_aborted; /* overflow */
@ -210,7 +224,13 @@ static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
/* image cache entry table */
slen = snprintf(buffer, sizeof buffer,
"<table class=\"config\">\n"
"<tr><th>Entry</th><th>Content Key</th><th>Redraw Count</th><th>Conversion Count</th><th>Last Redraw</th><th>Bitmap Age</th><th>Bitmap Size</th></tr>\n");
"<tr><th>Entry</th>"
"<th>Content Key</th>"
"<th>Redraw Count</th>"
"<th>Conversion Count</th>"
"<th>Last Redraw</th>"
"<th>Bitmap Age</th>"
"<th>Bitmap Size</th></tr>\n");
do {
res = image_cache_snentryf(buffer + slen, sizeof buffer - slen,
cent_loop,

View File

@ -171,8 +171,6 @@ static void image_cache_stats_bitmap_add(struct image_cache_entry_s *centry)
image_cache->max_bitmap_count_size = image_cache->total_bitmap_size;
}
centry->conversion_count++;
if (centry->conversion_count == 2) {
image_cache->total_extra_conversions_count++;
}
@ -530,75 +528,104 @@ nserror image_cache_remove(struct content *content)
int image_cache_snsummaryf(char *string, size_t size, const char *fmt)
{
size_t slen = 0; /* current output string length */
int fmtc = 0; /* current index into format string */
bool pct;
unsigned int op_count;
slen += snprintf(string + slen, size - slen,
"<p>Configured limit of %ld hysteresis of %ld",
image_cache->params.limit, image_cache->params.hysteresis);
slen += snprintf(string + slen, size - slen,
"<p>Total bitmap size in use %ld (in %d)",
image_cache->total_bitmap_size,
image_cache->bitmap_count);
uint64_t op_size;
op_count = image_cache->hit_count +
image_cache->miss_count +
image_cache->fail_count;
slen += snprintf(string + slen, size - slen,
"<p>Age %ds", image_cache->current_age / 1000);
slen += snprintf(string + slen, size - slen,
"<p>Peak size %ld (in %d)",
image_cache->max_bitmap_size,
image_cache->max_bitmap_size_count );
slen += snprintf(string + slen, size - slen,
"<p>Peak image count %d (size %ld)",
image_cache->max_bitmap_count,
image_cache->max_bitmap_count_size);
if (op_count > 0) {
uint64_t op_size;
op_size = image_cache->hit_size +
image_cache->miss_size +
image_cache->fail_size;
slen += snprintf(string + slen, size - slen,
"<p>Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
op_count,
image_cache->hit_count,
image_cache->miss_count,
image_cache->fail_count,
(image_cache->hit_count * 100) / op_count,
(image_cache->miss_count * 100) / op_count,
(image_cache->fail_count * 100) / op_count);
while((slen < size) && (fmt[fmtc] != 0)) {
if (fmt[fmtc] == '%') {
fmtc++;
slen += snprintf(string + slen, size - slen,
"<p>Cache total/hit/miss/fail (size) %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64" (100%%/%"PRIu64"%%/%"PRIu64"%%/%"PRIu64"%%)",
op_size,
image_cache->hit_size,
image_cache->miss_size,
image_cache->fail_size,
(image_cache->hit_size * 100) / op_size,
(image_cache->miss_size * 100) / op_size,
(image_cache->fail_size * 100) / op_size);
/* check for percentage modifier */
if (fmt[fmtc] == 'p') {
fmtc++;
pct = true;
} else {
pct = false;
}
slen += snprintf(string + slen, size - slen,
"<p>Total images never rendered: %d (includes %d that were converted)",
image_cache->total_unrendered,
image_cache->specultive_miss_count);
#define FMTCHR(chr,fmt,var) case chr : \
slen += snprintf(string + slen, size - slen, "%"#fmt, image_cache->var); break
slen += snprintf(string + slen, size - slen,
"<p>Total number of excessive conversions: %d (from %d images converted more than once)",
image_cache->total_extra_conversions,
image_cache->total_extra_conversions_count);
#define FMTPCHR(chr,fmt,var,div) \
case chr : \
if (pct) { \
if (div > 0) { \
slen += snprintf(string + slen, size - slen, "%zd", (uint64_t)((image_cache->var * 100) / div)); \
} else { \
slen += snprintf(string + slen, size - slen, "100"); \
} \
} else { \
slen += snprintf(string + slen, size - slen, "%"#fmt, image_cache->var); \
} break
switch (fmt[fmtc]) {
case '%':
string[slen] = '%';
slen++;
break;
FMTCHR('a', zd, params.limit);
FMTCHR('b', zd, params.hysteresis);
FMTCHR('c', zd, total_bitmap_size);
FMTCHR('d', d, bitmap_count);
FMTCHR('e', d, current_age / 1000);
FMTCHR('f', zd, max_bitmap_size);
FMTCHR('g', d, max_bitmap_size_count);
FMTCHR('h', d, max_bitmap_count);
FMTCHR('i', zd, max_bitmap_count_size);
case 'j':
slen += snprintf(string + slen, size - slen,
"<p>Bitmap of size %d had most (%d) conversions",
image_cache->peak_conversions_size,
image_cache->peak_conversions);
"%d", pct?100:op_count);
break;
FMTPCHR('k', d, hit_count, op_count);
FMTPCHR('l', d, miss_count, op_count);
FMTPCHR('m', d, fail_count, op_count);
case 'n':
slen += snprintf(string + slen, size - slen,
"%zd", pct?100:op_size);
break;
FMTPCHR('o', zd, hit_size, op_size);
FMTPCHR('q', zd, miss_size, op_size);
FMTPCHR('r', zd, fail_size, op_size);
FMTCHR('s', d, total_unrendered);
FMTCHR('t', d, specultive_miss_count);
FMTCHR('u', d, total_extra_conversions);
FMTCHR('v', d, total_extra_conversions_count);
FMTCHR('w', d, peak_conversions_size);
FMTCHR('x', d, peak_conversions);
}
#undef FMTCHR
#undef FMTPCHR
fmtc++;
} else {
string[slen] = fmt[fmtc];
slen++;
fmtc++;
}
}
/* Ensure that we NUL-terminate the output */
string[min(slen, size - 1)] = '\0';
return slen;
}
@ -750,4 +777,3 @@ content_type image_cache_content_type(void)
{
return CONTENT_IMAGE;
}

View File

@ -97,7 +97,7 @@ struct bitmap *image_cache_find_bitmap(struct content *c);
bool image_cache_speculate(struct content *c);
/**
* Fill a buffer with an option using a format.
* Fill a buffer with information about a cache entry using a format.
*
* The format string is copied into the output buffer with the
* following replaced:
@ -116,7 +116,54 @@ bool image_cache_speculate(struct content *c);
int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
const char *fmt);
/** cache summary */
/**
* Fill a buffer with information about the image cache using a format.
*
* The format string is copied into the output buffer with the
* following replaced:
*
* a Configured cache limit size
* b Configured cache hysteresis size
* c Current caches total consumed size
* d Number of images currently in the cache
* e The age of the cache
* f The largest amount of space the cache has occupied since initialisation
* g The number of objetcs when the cache was at its largest
* h The largest number of images in the cache since initialisation
* i The size of the cache when the largest number of objects occoured
* j The total number of read operations performed on the cache
* k The total number of read operations satisfied from the cache without
* conversion.
* l The total number of read operations satisfied from the cache which
* required a conversion.
* m The total number of read operations which could not be sucessfully
* returned. ie. not available in cache and conversion failed.
* n The total size of read operations performed on the cache
* o The total size of read operations satisfied from the cache without
* conversion.
* q The total size of read operations satisfied from the cache which
* required a conversion.
* r The total size of read operations which could not be sucessfully
* returned. ie. not available in cache and conversion failed.
* s The number of images which were placed in the cache but never read.
* t The number of images that were converted on insertion into teh cache which were subsequently never used.
* u The number of times an image was converted after the first
* v The number of images that had extra conversions performed.
* w Size of the image that was converted (read missed cache) highest number
* of times.
* x The number of times the image that was converted (read missed cache)
* highest number of times.
*
* format modifiers:
* A p before the value modifies the replacement to be a percentage.
*
*
* \param string The buffer in which to place the results.
* \param size The size of the string buffer.
* \param fmt The format string.
* \return The number of bytes written to \a string or -1 on error
*/
int image_cache_snsummaryf(char *string, size_t size, const char *fmt);
/********* Image content handler generic cache callbacks ************/