1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-01-12 09:17:37 +03:00

Cleanups and new limit APIs for dictionaries

* include/libxml/dict.h dict.c: adding 2 new functions xmlDictGetUsage
  and xmlDictSetLimit allowing to review the amount of memory allocated
  for dictionary strings. Aslo cleanup of various signed int used as
  size values in the code.
This commit is contained in:
Daniel Veillard 2012-07-25 16:32:18 +08:00
parent 6f6feba876
commit 7c693dad23
2 changed files with 139 additions and 60 deletions

193
dict.c
View File

@ -19,6 +19,7 @@
#define IN_LIBXML
#include "libxml.h"
#include <limits.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@ -93,7 +94,7 @@ typedef xmlDictEntry *xmlDictEntryPtr;
struct _xmlDictEntry {
struct _xmlDictEntry *next;
const xmlChar *name;
int len;
unsigned int len;
int valid;
unsigned long okey;
};
@ -104,8 +105,8 @@ struct _xmlDictStrings {
xmlDictStringsPtr next;
xmlChar *free;
xmlChar *end;
int size;
int nbStrings;
size_t size;
size_t nbStrings;
xmlChar array[1];
};
/*
@ -115,13 +116,15 @@ struct _xmlDict {
int ref_counter;
struct _xmlDictEntry *dict;
int size;
int nbElems;
size_t size;
unsigned int nbElems;
xmlDictStringsPtr strings;
struct _xmlDict *subdict;
/* used for randomization */
int seed;
/* used to impose a limit on size */
size_t limit;
};
/*
@ -213,17 +216,18 @@ xmlDictCleanup(void) {
* xmlDictAddString:
* @dict: the dictionnary
* @name: the name of the userdata
* @len: the length of the name, if -1 it is recomputed
* @len: the length of the name
*
* Add the string to the array[s]
*
* Returns the pointer of the local string, or NULL in case of error.
*/
static const xmlChar *
xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
xmlDictStringsPtr pool;
const xmlChar *ret;
int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
size_t limit = 0;
#ifdef DICT_DEBUG_PATTERNS
fprintf(stderr, "-");
@ -233,15 +237,20 @@ xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) {
if (pool->end - pool->free > namelen)
goto found_pool;
if (pool->size > size) size = pool->size;
limit += pool->size;
pool = pool->next;
}
/*
* Not found, need to allocate
*/
if (pool == NULL) {
if ((dict->limit > 0) && (limit > dict->limit)) {
return(NULL);
}
if (size == 0) size = 1000;
else size *= 4; /* exponential growth */
if (size < 4 * namelen)
if (size < 4 * namelen)
size = 4 * namelen; /* just in case ! */
pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
if (pool == NULL)
@ -271,19 +280,20 @@ found_pool:
* @prefix: the prefix of the userdata
* @plen: the prefix length
* @name: the name of the userdata
* @len: the length of the name, if -1 it is recomputed
* @len: the length of the name
*
* Add the QName to the array[s]
*
* Returns the pointer of the local string, or NULL in case of error.
*/
static const xmlChar *
xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
const xmlChar *name, int namelen)
xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
const xmlChar *name, unsigned int namelen)
{
xmlDictStringsPtr pool;
const xmlChar *ret;
int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
size_t limit = 0;
if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
@ -295,12 +305,17 @@ xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen,
if (pool->end - pool->free > namelen + plen + 1)
goto found_pool;
if (pool->size > size) size = pool->size;
limit += pool->size;
pool = pool->next;
}
/*
* Not found, need to allocate
*/
if (pool == NULL) {
if ((dict->limit > 0) && (limit > dict->limit)) {
return(NULL);
}
if (size == 0) size = 1000;
else size *= 4; /* exponential growth */
if (size < 4 * (namelen + plen + 1))
@ -517,6 +532,7 @@ xmlDictCreate(void) {
dict = xmlMalloc(sizeof(xmlDict));
if (dict) {
dict->ref_counter = 1;
dict->limit = 0;
dict->size = MIN_DICT_SIZE;
dict->nbElems = 0;
@ -594,9 +610,9 @@ xmlDictReference(xmlDictPtr dict) {
* Returns 0 in case of success, -1 in case of failure
*/
static int
xmlDictGrow(xmlDictPtr dict, int size) {
xmlDictGrow(xmlDictPtr dict, size_t size) {
unsigned long key, okey;
int oldsize, i;
size_t oldsize, i;
xmlDictEntryPtr iter, next;
struct _xmlDictEntry *olddict;
#ifdef DEBUG_GROW
@ -713,7 +729,7 @@ xmlDictGrow(xmlDictPtr dict, int size) {
#ifdef DEBUG_GROW
xmlGenericError(xmlGenericErrorContext,
"xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
"xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
#endif
return(ret);
@ -728,7 +744,7 @@ xmlDictGrow(xmlDictPtr dict, int size) {
*/
void
xmlDictFree(xmlDictPtr dict) {
int i;
size_t i;
xmlDictEntryPtr iter;
xmlDictEntryPtr next;
int inside_dict = 0;
@ -797,17 +813,24 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
xmlDictEntryPtr entry;
xmlDictEntryPtr insert;
const xmlChar *ret;
unsigned int l;
if ((dict == NULL) || (name == NULL))
return(NULL);
if (len < 0)
len = strlen((const char *) name);
l = strlen((const char *) name);
else
l = len;
if (((dict->limit > 0) && (l >= dict->limit)) ||
(l > INT_MAX / 2))
return(NULL);
/*
* Check for duplicate and insertion location.
*/
okey = xmlDictComputeKey(dict, name, len);
okey = xmlDictComputeKey(dict, name, l);
key = okey % dict->size;
if (dict->dict[key].valid == 0) {
insert = NULL;
@ -815,25 +838,25 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
for (insert = &(dict->dict[key]); insert->next != NULL;
insert = insert->next) {
#ifdef __GNUC__
if ((insert->okey == okey) && (insert->len == len)) {
if (!memcmp(insert->name, name, len))
if ((insert->okey == okey) && (insert->len == l)) {
if (!memcmp(insert->name, name, l))
return(insert->name);
}
#else
if ((insert->okey == okey) && (insert->len == len) &&
(!xmlStrncmp(insert->name, name, len)))
if ((insert->okey == okey) && (insert->l == l) &&
(!xmlStrncmp(insert->name, name, l)))
return(insert->name);
#endif
nbi++;
}
#ifdef __GNUC__
if ((insert->okey == okey) && (insert->len == len)) {
if (!memcmp(insert->name, name, len))
if ((insert->okey == okey) && (insert->len == l)) {
if (!memcmp(insert->name, name, l))
return(insert->name);
}
#else
if ((insert->okey == okey) && (insert->len == len) &&
(!xmlStrncmp(insert->name, name, len)))
if ((insert->okey == okey) && (insert->len == l) &&
(!xmlStrncmp(insert->name, name, l)))
return(insert->name);
#endif
}
@ -846,7 +869,7 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
(dict->subdict->size != MIN_DICT_SIZE)) ||
((dict->size != MIN_DICT_SIZE) &&
(dict->subdict->size == MIN_DICT_SIZE)))
skey = xmlDictComputeKey(dict->subdict, name, len);
skey = xmlDictComputeKey(dict->subdict, name, l);
else
skey = okey;
@ -857,32 +880,32 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
tmp = tmp->next) {
#ifdef __GNUC__
if ((tmp->okey == skey) && (tmp->len == len)) {
if (!memcmp(tmp->name, name, len))
if ((tmp->okey == skey) && (tmp->len == l)) {
if (!memcmp(tmp->name, name, l))
return(tmp->name);
}
#else
if ((tmp->okey == skey) && (tmp->len == len) &&
(!xmlStrncmp(tmp->name, name, len)))
if ((tmp->okey == skey) && (tmp->len == l) &&
(!xmlStrncmp(tmp->name, name, l)))
return(tmp->name);
#endif
nbi++;
}
#ifdef __GNUC__
if ((tmp->okey == skey) && (tmp->len == len)) {
if (!memcmp(tmp->name, name, len))
if ((tmp->okey == skey) && (tmp->len == l)) {
if (!memcmp(tmp->name, name, l))
return(tmp->name);
}
#else
if ((tmp->okey == skey) && (tmp->len == len) &&
(!xmlStrncmp(tmp->name, name, len)))
if ((tmp->okey == skey) && (tmp->len == l) &&
(!xmlStrncmp(tmp->name, name, l)))
return(tmp->name);
#endif
}
key = okey % dict->size;
}
ret = xmlDictAddString(dict, name, len);
ret = xmlDictAddString(dict, name, l);
if (ret == NULL)
return(NULL);
if (insert == NULL) {
@ -893,13 +916,13 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
return(NULL);
}
entry->name = ret;
entry->len = len;
entry->len = l;
entry->next = NULL;
entry->valid = 1;
entry->okey = okey;
if (insert != NULL)
if (insert != NULL)
insert->next = entry;
dict->nbElems++;
@ -928,17 +951,23 @@ const xmlChar *
xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
unsigned long key, okey, nbi = 0;
xmlDictEntryPtr insert;
unsigned int l;
if ((dict == NULL) || (name == NULL))
return(NULL);
if (len < 0)
len = strlen((const char *) name);
l = strlen((const char *) name);
else
l = len;
if (((dict->limit > 0) && (l >= dict->limit)) ||
(l > INT_MAX / 2))
return(NULL);
/*
* Check for duplicate and insertion location.
*/
okey = xmlDictComputeKey(dict, name, len);
okey = xmlDictComputeKey(dict, name, l);
key = okey % dict->size;
if (dict->dict[key].valid == 0) {
insert = NULL;
@ -946,25 +975,25 @@ xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
for (insert = &(dict->dict[key]); insert->next != NULL;
insert = insert->next) {
#ifdef __GNUC__
if ((insert->okey == okey) && (insert->len == len)) {
if (!memcmp(insert->name, name, len))
if ((insert->okey == okey) && (insert->len == l)) {
if (!memcmp(insert->name, name, l))
return(insert->name);
}
#else
if ((insert->okey == okey) && (insert->len == len) &&
(!xmlStrncmp(insert->name, name, len)))
if ((insert->okey == okey) && (insert->len == l) &&
(!xmlStrncmp(insert->name, name, l)))
return(insert->name);
#endif
nbi++;
}
#ifdef __GNUC__
if ((insert->okey == okey) && (insert->len == len)) {
if (!memcmp(insert->name, name, len))
if ((insert->okey == okey) && (insert->len == l)) {
if (!memcmp(insert->name, name, l))
return(insert->name);
}
#else
if ((insert->okey == okey) && (insert->len == len) &&
(!xmlStrncmp(insert->name, name, len)))
if ((insert->okey == okey) && (insert->len == l) &&
(!xmlStrncmp(insert->name, name, l)))
return(insert->name);
#endif
}
@ -977,7 +1006,7 @@ xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
(dict->subdict->size != MIN_DICT_SIZE)) ||
((dict->size != MIN_DICT_SIZE) &&
(dict->subdict->size == MIN_DICT_SIZE)))
skey = xmlDictComputeKey(dict->subdict, name, len);
skey = xmlDictComputeKey(dict->subdict, name, l);
else
skey = okey;
@ -988,25 +1017,25 @@ xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
tmp = tmp->next) {
#ifdef __GNUC__
if ((tmp->okey == skey) && (tmp->len == len)) {
if (!memcmp(tmp->name, name, len))
if ((tmp->okey == skey) && (tmp->len == l)) {
if (!memcmp(tmp->name, name, l))
return(tmp->name);
}
#else
if ((tmp->okey == skey) && (tmp->len == len) &&
(!xmlStrncmp(tmp->name, name, len)))
if ((tmp->okey == skey) && (tmp->len == l) &&
(!xmlStrncmp(tmp->name, name, l)))
return(tmp->name);
#endif
nbi++;
}
#ifdef __GNUC__
if ((tmp->okey == skey) && (tmp->len == len)) {
if (!memcmp(tmp->name, name, len))
if ((tmp->okey == skey) && (tmp->len == l)) {
if (!memcmp(tmp->name, name, l))
return(tmp->name);
}
#else
if ((tmp->okey == skey) && (tmp->len == len) &&
(!xmlStrncmp(tmp->name, name, len)))
if ((tmp->okey == skey) && (tmp->len == l) &&
(!xmlStrncmp(tmp->name, name, l)))
return(tmp->name);
#endif
}
@ -1032,7 +1061,7 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
xmlDictEntryPtr entry;
xmlDictEntryPtr insert;
const xmlChar *ret;
int len, plen, l;
unsigned int len, plen, l;
if ((dict == NULL) || (name == NULL))
return(NULL);
@ -1108,7 +1137,7 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
entry->valid = 1;
entry->okey = okey;
if (insert != NULL)
if (insert != NULL)
insert->next = entry;
dict->nbElems++;
@ -1166,6 +1195,50 @@ xmlDictSize(xmlDictPtr dict) {
return(dict->nbElems);
}
/**
* xmlDictSetLimit:
* @dict: the dictionnary
* @limit: the limit in bytes
*
* Set a size limit for the dictionary
* Added in 2.9.0
*
* Returns the previous limit of the dictionary or 0
*/
size_t
xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
size_t ret;
if (dict == NULL)
return(0);
ret = dict->limit;
dict->limit = limit;
return(ret);
}
/**
* xmlDictGetUsage:
* @dict: the dictionnary
*
* Get how much memory is used by a dictionary for strings
* Added in 2.9.0
*
* Returns the amount of strings allocated
*/
size_t
xmlDictGetUsage(xmlDictPtr dict) {
xmlDictStringsPtr pool;
size_t limit = 0;
if (dict == NULL)
return(0);
pool = dict->strings;
while (pool != NULL) {
limit += pool->size;
pool = pool->next;
}
return(limit);
}
#define bottom_dict
#include "elfgcchack.h"

View File

@ -11,6 +11,7 @@
#ifndef __XML_DICT_H__
#define __XML_DICT_H__
#include <limits.h>
#include <libxml/xmlversion.h>
#include <libxml/tree.h>
@ -34,6 +35,11 @@ XMLPUBFUN int XMLCALL xmlInitializeDict(void);
*/
XMLPUBFUN xmlDictPtr XMLCALL
xmlDictCreate (void);
XMLPUBFUN size_t XMLCALL
xmlDictSetLimit (xmlDictPtr dict,
size_t limit);
XMLPUBFUN size_t XMLCALL
xmlDictGetUsage (xmlDictPtr dict);
XMLPUBFUN xmlDictPtr XMLCALL
xmlDictCreateSub(xmlDictPtr sub);
XMLPUBFUN int XMLCALL