#define IN_LIBXML
#include "libxml.h"
+#include <limits.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#endif /* WITH_BIG_KEY */
/*
- * An entry in the dictionnary
+ * An entry in the dictionary
*/
typedef struct _xmlDictEntry xmlDictEntry;
typedef xmlDictEntry *xmlDictEntryPtr;
struct _xmlDictEntry {
struct _xmlDictEntry *next;
const xmlChar *name;
- int len;
+ unsigned int len;
int valid;
unsigned long okey;
};
xmlDictStringsPtr next;
xmlChar *free;
xmlChar *end;
- int size;
- int nbStrings;
+ size_t size;
+ size_t nbStrings;
xmlChar array[1];
};
/*
- * The entire dictionnary
+ * The entire dictionary
*/
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;
};
/*
/*
* Internal data for random function, protected by xmlDictMutex
*/
-unsigned int rand_seed = 0;
+static unsigned int rand_seed = 0;
#endif
#endif
* xmlInitializeDict:
*
* Do the dictionary mutex initialization.
- * this function is not thread safe, initialization should
- * preferably be done once at startup
+ * this function is deprecated
*
* Returns 0 if initialization was already done, and 1 if that
* call led to the initialization
*/
int xmlInitializeDict(void) {
+ return(0);
+}
+
+/**
+ * __xmlInitializeDict:
+ *
+ * This function is not public
+ * Do the dictionary mutex initialization.
+ * this function is not thread safe, initialization should
+ * normally be done once at setup when called from xmlOnceInit()
+ * we may also land in this code if thread support is not compiled in
+ *
+ * Returns 0 if initialization was already done, and 1 if that
+ * call led to the initialization
+ */
+int __xmlInitializeDict(void) {
if (xmlDictInitialized)
return(1);
int ret;
if (xmlDictInitialized == 0)
- xmlInitializeDict();
+ __xmlInitializeDict();
xmlRMutexLock(xmlDictMutex);
#ifdef HAVE_RAND_R
/*
* xmlDictAddString:
- * @dict: the dictionnary
+ * @dict: the dictionary
* @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, "-");
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)
/*
* xmlDictAddQString:
- * @dict: the dictionnary
+ * @dict: the dictionary
* @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));
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))
value += 30 * (*prefix);
if (len > 10) {
- value += name[len - (plen + 1 + 1)];
+ int offset = len - (plen + 1 + 1);
+ if (offset < 0)
+ offset = len - (10 + 1);
+ value += name[offset];
len = 10;
if (plen > 10)
plen = 10;
*
* Create a new dictionary
*
- * Returns the newly created dictionnary, or NULL if an error occured.
+ * Returns the newly created dictionary, or NULL if an error occurred.
*/
xmlDictPtr
xmlDictCreate(void) {
xmlDictPtr dict;
if (!xmlDictInitialized)
- if (!xmlInitializeDict())
+ if (!__xmlInitializeDict())
return(NULL);
#ifdef DICT_DEBUG_PATTERNS
dict = xmlMalloc(sizeof(xmlDict));
if (dict) {
dict->ref_counter = 1;
+ dict->limit = 0;
dict->size = MIN_DICT_SIZE;
dict->nbElems = 0;
/**
* xmlDictCreateSub:
- * @sub: an existing dictionnary
+ * @sub: an existing dictionary
*
* Create a new dictionary, inheriting strings from the read-only
- * dictionnary @sub. On lookup, strings are first searched in the
- * new dictionnary, then in @sub, and if not found are created in the
- * new dictionnary.
+ * dictionary @sub. On lookup, strings are first searched in the
+ * new dictionary, then in @sub, and if not found are created in the
+ * new dictionary.
*
- * Returns the newly created dictionnary, or NULL if an error occured.
+ * Returns the newly created dictionary, or NULL if an error occurred.
*/
xmlDictPtr
xmlDictCreateSub(xmlDictPtr sub) {
/**
* xmlDictReference:
- * @dict: the dictionnary
+ * @dict: the dictionary
*
* Increment the reference counter of a dictionary
*
int
xmlDictReference(xmlDictPtr dict) {
if (!xmlDictInitialized)
- if (!xmlInitializeDict())
+ if (!__xmlInitializeDict())
return(-1);
if (dict == NULL) return -1;
/**
* xmlDictGrow:
- * @dict: the dictionnary
- * @size: the new size of the dictionnary
+ * @dict: the dictionary
+ * @size: the new size of the dictionary
*
- * resize the dictionnary
+ * resize the dictionary
*
* 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
} else {
/*
* we don't have much ways to alert from herei
- * result is loosing an entry and unicity garantee
+ * result is losing an entry and unicity guarantee
*/
ret = -1;
}
#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);
/**
* xmlDictFree:
- * @dict: the dictionnary
+ * @dict: the dictionary
*
* Free the hash @dict and its contents. The userdata is
* deallocated with @f if provided.
*/
void
xmlDictFree(xmlDictPtr dict) {
- int i;
+ size_t i;
xmlDictEntryPtr iter;
xmlDictEntryPtr next;
int inside_dict = 0;
return;
if (!xmlDictInitialized)
- if (!xmlInitializeDict())
+ if (!__xmlInitializeDict())
return;
/* decrement the counter, it may be shared by a parser and docs */
/**
* xmlDictLookup:
- * @dict: the dictionnary
+ * @dict: the dictionary
* @name: the name of the userdata
* @len: the length of the name, if -1 it is recomputed
*
- * Add the @name to the dictionnary @dict if not present.
+ * Add the @name to the dictionary @dict if not present.
*
* Returns the internal copy of the name or NULL in case of internal error
*/
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;
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
}
(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;
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) {
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++;
/**
* xmlDictExists:
- * @dict: the dictionnary
+ * @dict: the dictionary
* @name: the name of the userdata
* @len: the length of the name, if -1 it is recomputed
*
- * Check if the @name exists in the dictionnary @dict.
+ * Check if the @name exists in the dictionary @dict.
*
* Returns the internal copy of the name or NULL if not found.
*/
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;
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
}
(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;
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
}
/**
* xmlDictQLookup:
- * @dict: the dictionnary
+ * @dict: the dictionary
* @prefix: the prefix
* @name: the name
*
xmlDictEntryPtr entry;
xmlDictEntryPtr insert;
const xmlChar *ret;
- int len, plen, l;
+ unsigned int len, plen, l;
if ((dict == NULL) || (name == NULL))
return(NULL);
entry->valid = 1;
entry->okey = okey;
- if (insert != NULL)
+ if (insert != NULL)
insert->next = entry;
dict->nbElems++;
/**
* xmlDictOwns:
- * @dict: the dictionnary
+ * @dict: the dictionary
* @str: the string
*
* check if a string is owned by the disctionary
/**
* xmlDictSize:
- * @dict: the dictionnary
+ * @dict: the dictionary
*
* Query the number of elements installed in the hash @dict.
*
- * Returns the number of elements in the dictionnary or
+ * Returns the number of elements in the dictionary or
* -1 in case of error
*/
int
return(dict->nbElems);
}
+/**
+ * xmlDictSetLimit:
+ * @dict: the dictionary
+ * @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 dictionary
+ *
+ * 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"