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:
parent
6f6feba876
commit
7c693dad23
193
dict.c
193
dict.c
@ -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"
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user