Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * dict.c: dictionary of reusable strings, just used to avoid allocation
      3  *         and freeing operations.
      4  *
      5  * Copyright (C) 2003-2012 Daniel Veillard.
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     12  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     13  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
     14  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
     15  *
     16  * Author: daniel (at) veillard.com
     17  */
     18 
     19 #define IN_LIBXML
     20 #include "libxml.h"
     21 
     22 #include <limits.h>
     23 #ifdef HAVE_STDLIB_H
     24 #include <stdlib.h>
     25 #endif
     26 #ifdef HAVE_TIME_H
     27 #include <time.h>
     28 #endif
     29 
     30 /*
     31  * Following http://www.ocert.org/advisories/ocert-2011-003.html
     32  * it seems that having hash randomization might be a good idea
     33  * when using XML with untrusted data
     34  * Note1: that it works correctly only if compiled with WITH_BIG_KEY
     35  *  which is the default.
     36  * Note2: the fast function used for a small dict won't protect very
     37  *  well but since the attack is based on growing a very big hash
     38  *  list we will use the BigKey algo as soon as the hash size grows
     39  *  over MIN_DICT_SIZE so this actually works
     40  */
     41 #if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME)
     42 #define DICT_RANDOMIZATION
     43 #endif
     44 
     45 #include <string.h>
     46 #ifdef HAVE_STDINT_H
     47 #include <stdint.h>
     48 #else
     49 #ifdef HAVE_INTTYPES_H
     50 #include <inttypes.h>
     51 #elif defined(_WIN32)
     52 typedef unsigned __int32 uint32_t;
     53 #endif
     54 #endif
     55 #include <libxml/tree.h>
     56 #include <libxml/dict.h>
     57 #include <libxml/xmlmemory.h>
     58 #include <libxml/xmlerror.h>
     59 #include <libxml/globals.h>
     60 
     61 /* #define DEBUG_GROW */
     62 /* #define DICT_DEBUG_PATTERNS */
     63 
     64 #define MAX_HASH_LEN 3
     65 #define MIN_DICT_SIZE 128
     66 #define MAX_DICT_HASH 8 * 2048
     67 #define WITH_BIG_KEY
     68 
     69 #ifdef WITH_BIG_KEY
     70 #define xmlDictComputeKey(dict, name, len)                              \
     71     (((dict)->size == MIN_DICT_SIZE) ?                                  \
     72      xmlDictComputeFastKey(name, len, (dict)->seed) :                   \
     73      xmlDictComputeBigKey(name, len, (dict)->seed))
     74 
     75 #define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
     76     (((prefix) == NULL) ?                                               \
     77       (xmlDictComputeKey(dict, name, len)) :                             \
     78       (((dict)->size == MIN_DICT_SIZE) ?                                \
     79        xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) :	\
     80        xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed)))
     81 
     82 #else /* !WITH_BIG_KEY */
     83 #define xmlDictComputeKey(dict, name, len)                              \
     84         xmlDictComputeFastKey(name, len, (dict)->seed)
     85 #define xmlDictComputeQKey(dict, prefix, plen, name, len)               \
     86         xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed)
     87 #endif /* WITH_BIG_KEY */
     88 
     89 /*
     90  * An entry in the dictionary
     91  */
     92 typedef struct _xmlDictEntry xmlDictEntry;
     93 typedef xmlDictEntry *xmlDictEntryPtr;
     94 struct _xmlDictEntry {
     95     struct _xmlDictEntry *next;
     96     const xmlChar *name;
     97     unsigned int len;
     98     int valid;
     99     unsigned long okey;
    100 };
    101 
    102 typedef struct _xmlDictStrings xmlDictStrings;
    103 typedef xmlDictStrings *xmlDictStringsPtr;
    104 struct _xmlDictStrings {
    105     xmlDictStringsPtr next;
    106     xmlChar *free;
    107     xmlChar *end;
    108     size_t size;
    109     size_t nbStrings;
    110     xmlChar array[1];
    111 };
    112 /*
    113  * The entire dictionary
    114  */
    115 struct _xmlDict {
    116     int ref_counter;
    117 
    118     struct _xmlDictEntry *dict;
    119     size_t size;
    120     unsigned int nbElems;
    121     xmlDictStringsPtr strings;
    122 
    123     struct _xmlDict *subdict;
    124     /* used for randomization */
    125     int seed;
    126     /* used to impose a limit on size */
    127     size_t limit;
    128 };
    129 
    130 /*
    131  * A mutex for modifying the reference counter for shared
    132  * dictionaries.
    133  */
    134 static xmlRMutexPtr xmlDictMutex = NULL;
    135 
    136 /*
    137  * Whether the dictionary mutex was initialized.
    138  */
    139 static int xmlDictInitialized = 0;
    140 
    141 #ifdef DICT_RANDOMIZATION
    142 #ifdef HAVE_RAND_R
    143 /*
    144  * Internal data for random function, protected by xmlDictMutex
    145  */
    146 static unsigned int rand_seed = 0;
    147 #endif
    148 #endif
    149 
    150 /**
    151  * xmlInitializeDict:
    152  *
    153  * Do the dictionary mutex initialization.
    154  * this function is deprecated
    155  *
    156  * Returns 0 if initialization was already done, and 1 if that
    157  * call led to the initialization
    158  */
    159 int xmlInitializeDict(void) {
    160     return(0);
    161 }
    162 
    163 /**
    164  * __xmlInitializeDict:
    165  *
    166  * This function is not public
    167  * Do the dictionary mutex initialization.
    168  * this function is not thread safe, initialization should
    169  * normally be done once at setup when called from xmlOnceInit()
    170  * we may also land in this code if thread support is not compiled in
    171  *
    172  * Returns 0 if initialization was already done, and 1 if that
    173  * call led to the initialization
    174  */
    175 int __xmlInitializeDict(void) {
    176     if (xmlDictInitialized)
    177         return(1);
    178 
    179     if ((xmlDictMutex = xmlNewRMutex()) == NULL)
    180         return(0);
    181     xmlRMutexLock(xmlDictMutex);
    182 
    183 #ifdef DICT_RANDOMIZATION
    184 #ifdef HAVE_RAND_R
    185     rand_seed = time(NULL);
    186     rand_r(& rand_seed);
    187 #else
    188     srand(time(NULL));
    189 #endif
    190 #endif
    191     xmlDictInitialized = 1;
    192     xmlRMutexUnlock(xmlDictMutex);
    193     return(1);
    194 }
    195 
    196 #ifdef DICT_RANDOMIZATION
    197 int __xmlRandom(void) {
    198     int ret;
    199 
    200     if (xmlDictInitialized == 0)
    201         __xmlInitializeDict();
    202 
    203     xmlRMutexLock(xmlDictMutex);
    204 #ifdef HAVE_RAND_R
    205     ret = rand_r(& rand_seed);
    206 #else
    207     ret = rand();
    208 #endif
    209     xmlRMutexUnlock(xmlDictMutex);
    210     return(ret);
    211 }
    212 #endif
    213 
    214 /**
    215  * xmlDictCleanup:
    216  *
    217  * Free the dictionary mutex. Do not call unless sure the library
    218  * is not in use anymore !
    219  */
    220 void
    221 xmlDictCleanup(void) {
    222     if (!xmlDictInitialized)
    223         return;
    224 
    225     xmlFreeRMutex(xmlDictMutex);
    226 
    227     xmlDictInitialized = 0;
    228 }
    229 
    230 /*
    231  * xmlDictAddString:
    232  * @dict: the dictionary
    233  * @name: the name of the userdata
    234  * @len: the length of the name
    235  *
    236  * Add the string to the array[s]
    237  *
    238  * Returns the pointer of the local string, or NULL in case of error.
    239  */
    240 static const xmlChar *
    241 xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
    242     xmlDictStringsPtr pool;
    243     const xmlChar *ret;
    244     size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
    245     size_t limit = 0;
    246 
    247 #ifdef DICT_DEBUG_PATTERNS
    248     fprintf(stderr, "-");
    249 #endif
    250     pool = dict->strings;
    251     while (pool != NULL) {
    252 	if ((size_t)(pool->end - pool->free) > namelen)
    253 	    goto found_pool;
    254 	if (pool->size > size) size = pool->size;
    255         limit += pool->size;
    256 	pool = pool->next;
    257     }
    258     /*
    259      * Not found, need to allocate
    260      */
    261     if (pool == NULL) {
    262         if ((dict->limit > 0) && (limit > dict->limit)) {
    263             return(NULL);
    264         }
    265 
    266         if (size == 0) size = 1000;
    267 	else size *= 4; /* exponential growth */
    268         if (size < 4 * namelen)
    269 	    size = 4 * namelen; /* just in case ! */
    270 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
    271 	if (pool == NULL)
    272 	    return(NULL);
    273 	pool->size = size;
    274 	pool->nbStrings = 0;
    275 	pool->free = &pool->array[0];
    276 	pool->end = &pool->array[size];
    277 	pool->next = dict->strings;
    278 	dict->strings = pool;
    279 #ifdef DICT_DEBUG_PATTERNS
    280         fprintf(stderr, "+");
    281 #endif
    282     }
    283 found_pool:
    284     ret = pool->free;
    285     memcpy(pool->free, name, namelen);
    286     pool->free += namelen;
    287     *(pool->free++) = 0;
    288     pool->nbStrings++;
    289     return(ret);
    290 }
    291 
    292 /*
    293  * xmlDictAddQString:
    294  * @dict: the dictionary
    295  * @prefix: the prefix of the userdata
    296  * @plen: the prefix length
    297  * @name: the name of the userdata
    298  * @len: the length of the name
    299  *
    300  * Add the QName to the array[s]
    301  *
    302  * Returns the pointer of the local string, or NULL in case of error.
    303  */
    304 static const xmlChar *
    305 xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
    306                  const xmlChar *name, unsigned int namelen)
    307 {
    308     xmlDictStringsPtr pool;
    309     const xmlChar *ret;
    310     size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
    311     size_t limit = 0;
    312 
    313     if (prefix == NULL) return(xmlDictAddString(dict, name, namelen));
    314 
    315 #ifdef DICT_DEBUG_PATTERNS
    316     fprintf(stderr, "=");
    317 #endif
    318     pool = dict->strings;
    319     while (pool != NULL) {
    320 	if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
    321 	    goto found_pool;
    322 	if (pool->size > size) size = pool->size;
    323         limit += pool->size;
    324 	pool = pool->next;
    325     }
    326     /*
    327      * Not found, need to allocate
    328      */
    329     if (pool == NULL) {
    330         if ((dict->limit > 0) && (limit > dict->limit)) {
    331             return(NULL);
    332         }
    333 
    334         if (size == 0) size = 1000;
    335 	else size *= 4; /* exponential growth */
    336         if (size < 4 * (namelen + plen + 1))
    337 	    size = 4 * (namelen + plen + 1); /* just in case ! */
    338 	pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
    339 	if (pool == NULL)
    340 	    return(NULL);
    341 	pool->size = size;
    342 	pool->nbStrings = 0;
    343 	pool->free = &pool->array[0];
    344 	pool->end = &pool->array[size];
    345 	pool->next = dict->strings;
    346 	dict->strings = pool;
    347 #ifdef DICT_DEBUG_PATTERNS
    348         fprintf(stderr, "+");
    349 #endif
    350     }
    351 found_pool:
    352     ret = pool->free;
    353     memcpy(pool->free, prefix, plen);
    354     pool->free += plen;
    355     *(pool->free++) = ':';
    356     memcpy(pool->free, name, namelen);
    357     pool->free += namelen;
    358     *(pool->free++) = 0;
    359     pool->nbStrings++;
    360     return(ret);
    361 }
    362 
    363 #ifdef WITH_BIG_KEY
    364 /*
    365  * xmlDictComputeBigKey:
    366  *
    367  * Calculate a hash key using a good hash function that works well for
    368  * larger hash table sizes.
    369  *
    370  * Hash function by "One-at-a-Time Hash" see
    371  * http://burtleburtle.net/bob/hash/doobs.html
    372  */
    373 
    374 static uint32_t
    375 xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) {
    376     uint32_t hash;
    377     int i;
    378 
    379     if (namelen <= 0 || data == NULL) return(0);
    380 
    381     hash = seed;
    382 
    383     for (i = 0;i < namelen; i++) {
    384         hash += data[i];
    385 	hash += (hash << 10);
    386 	hash ^= (hash >> 6);
    387     }
    388     hash += (hash << 3);
    389     hash ^= (hash >> 11);
    390     hash += (hash << 15);
    391 
    392     return hash;
    393 }
    394 
    395 /*
    396  * xmlDictComputeBigQKey:
    397  *
    398  * Calculate a hash key for two strings using a good hash function
    399  * that works well for larger hash table sizes.
    400  *
    401  * Hash function by "One-at-a-Time Hash" see
    402  * http://burtleburtle.net/bob/hash/doobs.html
    403  *
    404  * Neither of the two strings must be NULL.
    405  */
    406 static unsigned long
    407 xmlDictComputeBigQKey(const xmlChar *prefix, int plen,
    408                       const xmlChar *name, int len, int seed)
    409 {
    410     uint32_t hash;
    411     int i;
    412 
    413     hash = seed;
    414 
    415     for (i = 0;i < plen; i++) {
    416         hash += prefix[i];
    417 	hash += (hash << 10);
    418 	hash ^= (hash >> 6);
    419     }
    420     hash += ':';
    421     hash += (hash << 10);
    422     hash ^= (hash >> 6);
    423 
    424     for (i = 0;i < len; i++) {
    425         hash += name[i];
    426 	hash += (hash << 10);
    427 	hash ^= (hash >> 6);
    428     }
    429     hash += (hash << 3);
    430     hash ^= (hash >> 11);
    431     hash += (hash << 15);
    432 
    433     return hash;
    434 }
    435 #endif /* WITH_BIG_KEY */
    436 
    437 /*
    438  * xmlDictComputeFastKey:
    439  *
    440  * Calculate a hash key using a fast hash function that works well
    441  * for low hash table fill.
    442  */
    443 static unsigned long
    444 xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
    445     unsigned long value = seed;
    446 
    447     if (name == NULL) return(0);
    448     value = *name;
    449     value <<= 5;
    450     if (namelen > 10) {
    451         value += name[namelen - 1];
    452         namelen = 10;
    453     }
    454     switch (namelen) {
    455         case 10: value += name[9];
    456         /* Falls through. */
    457         case 9: value += name[8];
    458         /* Falls through. */
    459         case 8: value += name[7];
    460         /* Falls through. */
    461         case 7: value += name[6];
    462         /* Falls through. */
    463         case 6: value += name[5];
    464         /* Falls through. */
    465         case 5: value += name[4];
    466         /* Falls through. */
    467         case 4: value += name[3];
    468         /* Falls through. */
    469         case 3: value += name[2];
    470         /* Falls through. */
    471         case 2: value += name[1];
    472         /* Falls through. */
    473         default: break;
    474     }
    475     return(value);
    476 }
    477 
    478 /*
    479  * xmlDictComputeFastQKey:
    480  *
    481  * Calculate a hash key for two strings using a fast hash function
    482  * that works well for low hash table fill.
    483  *
    484  * Neither of the two strings must be NULL.
    485  */
    486 static unsigned long
    487 xmlDictComputeFastQKey(const xmlChar *prefix, int plen,
    488                        const xmlChar *name, int len, int seed)
    489 {
    490     unsigned long value = (unsigned long) seed;
    491 
    492     if (plen == 0)
    493 	value += 30 * (unsigned long) ':';
    494     else
    495 	value += 30 * (*prefix);
    496 
    497     if (len > 10) {
    498         int offset = len - (plen + 1 + 1);
    499 	if (offset < 0)
    500 	    offset = len - (10 + 1);
    501 	value += name[offset];
    502         len = 10;
    503 	if (plen > 10)
    504 	    plen = 10;
    505     }
    506     switch (plen) {
    507         case 10: value += prefix[9];
    508         /* Falls through. */
    509         case 9: value += prefix[8];
    510         /* Falls through. */
    511         case 8: value += prefix[7];
    512         /* Falls through. */
    513         case 7: value += prefix[6];
    514         /* Falls through. */
    515         case 6: value += prefix[5];
    516         /* Falls through. */
    517         case 5: value += prefix[4];
    518         /* Falls through. */
    519         case 4: value += prefix[3];
    520         /* Falls through. */
    521         case 3: value += prefix[2];
    522         /* Falls through. */
    523         case 2: value += prefix[1];
    524         /* Falls through. */
    525         case 1: value += prefix[0];
    526         /* Falls through. */
    527         default: break;
    528     }
    529     len -= plen;
    530     if (len > 0) {
    531         value += (unsigned long) ':';
    532 	len--;
    533     }
    534     switch (len) {
    535         case 10: value += name[9];
    536         /* Falls through. */
    537         case 9: value += name[8];
    538         /* Falls through. */
    539         case 8: value += name[7];
    540         /* Falls through. */
    541         case 7: value += name[6];
    542         /* Falls through. */
    543         case 6: value += name[5];
    544         /* Falls through. */
    545         case 5: value += name[4];
    546         /* Falls through. */
    547         case 4: value += name[3];
    548         /* Falls through. */
    549         case 3: value += name[2];
    550         /* Falls through. */
    551         case 2: value += name[1];
    552         /* Falls through. */
    553         case 1: value += name[0];
    554         /* Falls through. */
    555         default: break;
    556     }
    557     return(value);
    558 }
    559 
    560 /**
    561  * xmlDictCreate:
    562  *
    563  * Create a new dictionary
    564  *
    565  * Returns the newly created dictionary, or NULL if an error occurred.
    566  */
    567 xmlDictPtr
    568 xmlDictCreate(void) {
    569     xmlDictPtr dict;
    570 
    571     if (!xmlDictInitialized)
    572         if (!__xmlInitializeDict())
    573             return(NULL);
    574 
    575 #ifdef DICT_DEBUG_PATTERNS
    576     fprintf(stderr, "C");
    577 #endif
    578 
    579     dict = xmlMalloc(sizeof(xmlDict));
    580     if (dict) {
    581         dict->ref_counter = 1;
    582         dict->limit = 0;
    583 
    584         dict->size = MIN_DICT_SIZE;
    585 	dict->nbElems = 0;
    586         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
    587 	dict->strings = NULL;
    588 	dict->subdict = NULL;
    589         if (dict->dict) {
    590 	    memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry));
    591 #ifdef DICT_RANDOMIZATION
    592             dict->seed = __xmlRandom();
    593 #else
    594             dict->seed = 0;
    595 #endif
    596 	    return(dict);
    597         }
    598         xmlFree(dict);
    599     }
    600     return(NULL);
    601 }
    602 
    603 /**
    604  * xmlDictCreateSub:
    605  * @sub: an existing dictionary
    606  *
    607  * Create a new dictionary, inheriting strings from the read-only
    608  * dictionary @sub. On lookup, strings are first searched in the
    609  * new dictionary, then in @sub, and if not found are created in the
    610  * new dictionary.
    611  *
    612  * Returns the newly created dictionary, or NULL if an error occurred.
    613  */
    614 xmlDictPtr
    615 xmlDictCreateSub(xmlDictPtr sub) {
    616     xmlDictPtr dict = xmlDictCreate();
    617 
    618     if ((dict != NULL) && (sub != NULL)) {
    619 #ifdef DICT_DEBUG_PATTERNS
    620         fprintf(stderr, "R");
    621 #endif
    622         dict->seed = sub->seed;
    623         dict->subdict = sub;
    624 	xmlDictReference(dict->subdict);
    625     }
    626     return(dict);
    627 }
    628 
    629 /**
    630  * xmlDictReference:
    631  * @dict: the dictionary
    632  *
    633  * Increment the reference counter of a dictionary
    634  *
    635  * Returns 0 in case of success and -1 in case of error
    636  */
    637 int
    638 xmlDictReference(xmlDictPtr dict) {
    639     if (!xmlDictInitialized)
    640         if (!__xmlInitializeDict())
    641             return(-1);
    642 
    643     if (dict == NULL) return -1;
    644     xmlRMutexLock(xmlDictMutex);
    645     dict->ref_counter++;
    646     xmlRMutexUnlock(xmlDictMutex);
    647     return(0);
    648 }
    649 
    650 /**
    651  * xmlDictGrow:
    652  * @dict: the dictionary
    653  * @size: the new size of the dictionary
    654  *
    655  * resize the dictionary
    656  *
    657  * Returns 0 in case of success, -1 in case of failure
    658  */
    659 static int
    660 xmlDictGrow(xmlDictPtr dict, size_t size) {
    661     unsigned long key, okey;
    662     size_t oldsize, i;
    663     xmlDictEntryPtr iter, next;
    664     struct _xmlDictEntry *olddict;
    665 #ifdef DEBUG_GROW
    666     unsigned long nbElem = 0;
    667 #endif
    668     int ret = 0;
    669     int keep_keys = 1;
    670 
    671     if (dict == NULL)
    672 	return(-1);
    673     if (size < 8)
    674         return(-1);
    675     if (size > 8 * 2048)
    676 	return(-1);
    677 
    678 #ifdef DICT_DEBUG_PATTERNS
    679     fprintf(stderr, "*");
    680 #endif
    681 
    682     oldsize = dict->size;
    683     olddict = dict->dict;
    684     if (olddict == NULL)
    685         return(-1);
    686     if (oldsize == MIN_DICT_SIZE)
    687         keep_keys = 0;
    688 
    689     dict->dict = xmlMalloc(size * sizeof(xmlDictEntry));
    690     if (dict->dict == NULL) {
    691 	dict->dict = olddict;
    692 	return(-1);
    693     }
    694     memset(dict->dict, 0, size * sizeof(xmlDictEntry));
    695     dict->size = size;
    696 
    697     /*	If the two loops are merged, there would be situations where
    698 	a new entry needs to allocated and data copied into it from
    699 	the main dict. It is nicer to run through the array twice, first
    700 	copying all the elements in the main array (less probability of
    701 	allocate) and then the rest, so we only free in the second loop.
    702     */
    703     for (i = 0; i < oldsize; i++) {
    704 	if (olddict[i].valid == 0)
    705 	    continue;
    706 
    707 	if (keep_keys)
    708 	    okey = olddict[i].okey;
    709 	else
    710 	    okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len);
    711 	key = okey % dict->size;
    712 
    713 	if (dict->dict[key].valid == 0) {
    714 	    memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry));
    715 	    dict->dict[key].next = NULL;
    716 	    dict->dict[key].okey = okey;
    717 	} else {
    718 	    xmlDictEntryPtr entry;
    719 
    720 	    entry = xmlMalloc(sizeof(xmlDictEntry));
    721 	    if (entry != NULL) {
    722 		entry->name = olddict[i].name;
    723 		entry->len = olddict[i].len;
    724 		entry->okey = okey;
    725 		entry->next = dict->dict[key].next;
    726 		entry->valid = 1;
    727 		dict->dict[key].next = entry;
    728 	    } else {
    729 	        /*
    730 		 * we don't have much ways to alert from herei
    731 		 * result is losing an entry and unicity guarantee
    732 		 */
    733 	        ret = -1;
    734 	    }
    735 	}
    736 #ifdef DEBUG_GROW
    737 	nbElem++;
    738 #endif
    739     }
    740 
    741     for (i = 0; i < oldsize; i++) {
    742 	iter = olddict[i].next;
    743 	while (iter) {
    744 	    next = iter->next;
    745 
    746 	    /*
    747 	     * put back the entry in the new dict
    748 	     */
    749 
    750 	    if (keep_keys)
    751 		okey = iter->okey;
    752 	    else
    753 		okey = xmlDictComputeKey(dict, iter->name, iter->len);
    754 	    key = okey % dict->size;
    755 	    if (dict->dict[key].valid == 0) {
    756 		memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry));
    757 		dict->dict[key].next = NULL;
    758 		dict->dict[key].valid = 1;
    759 		dict->dict[key].okey = okey;
    760 		xmlFree(iter);
    761 	    } else {
    762 		iter->next = dict->dict[key].next;
    763 		iter->okey = okey;
    764 		dict->dict[key].next = iter;
    765 	    }
    766 
    767 #ifdef DEBUG_GROW
    768 	    nbElem++;
    769 #endif
    770 
    771 	    iter = next;
    772 	}
    773     }
    774 
    775     xmlFree(olddict);
    776 
    777 #ifdef DEBUG_GROW
    778     xmlGenericError(xmlGenericErrorContext,
    779 	    "xmlDictGrow : from %lu to %lu, %u elems\n", oldsize, size, nbElem);
    780 #endif
    781 
    782     return(ret);
    783 }
    784 
    785 /**
    786  * xmlDictFree:
    787  * @dict: the dictionary
    788  *
    789  * Free the hash @dict and its contents. The userdata is
    790  * deallocated with @f if provided.
    791  */
    792 void
    793 xmlDictFree(xmlDictPtr dict) {
    794     size_t i;
    795     xmlDictEntryPtr iter;
    796     xmlDictEntryPtr next;
    797     int inside_dict = 0;
    798     xmlDictStringsPtr pool, nextp;
    799 
    800     if (dict == NULL)
    801 	return;
    802 
    803     if (!xmlDictInitialized)
    804         if (!__xmlInitializeDict())
    805             return;
    806 
    807     /* decrement the counter, it may be shared by a parser and docs */
    808     xmlRMutexLock(xmlDictMutex);
    809     dict->ref_counter--;
    810     if (dict->ref_counter > 0) {
    811         xmlRMutexUnlock(xmlDictMutex);
    812         return;
    813     }
    814 
    815     xmlRMutexUnlock(xmlDictMutex);
    816 
    817     if (dict->subdict != NULL) {
    818         xmlDictFree(dict->subdict);
    819     }
    820 
    821     if (dict->dict) {
    822 	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
    823 	    iter = &(dict->dict[i]);
    824 	    if (iter->valid == 0)
    825 		continue;
    826 	    inside_dict = 1;
    827 	    while (iter) {
    828 		next = iter->next;
    829 		if (!inside_dict)
    830 		    xmlFree(iter);
    831 		dict->nbElems--;
    832 		inside_dict = 0;
    833 		iter = next;
    834 	    }
    835 	}
    836 	xmlFree(dict->dict);
    837     }
    838     pool = dict->strings;
    839     while (pool != NULL) {
    840         nextp = pool->next;
    841 	xmlFree(pool);
    842 	pool = nextp;
    843     }
    844     xmlFree(dict);
    845 }
    846 
    847 /**
    848  * xmlDictLookup:
    849  * @dict: the dictionary
    850  * @name: the name of the userdata
    851  * @len: the length of the name, if -1 it is recomputed
    852  *
    853  * Add the @name to the dictionary @dict if not present.
    854  *
    855  * Returns the internal copy of the name or NULL in case of internal error
    856  */
    857 const xmlChar *
    858 xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
    859     unsigned long key, okey, nbi = 0;
    860     xmlDictEntryPtr entry;
    861     xmlDictEntryPtr insert;
    862     const xmlChar *ret;
    863     unsigned int l;
    864 
    865     if ((dict == NULL) || (name == NULL))
    866 	return(NULL);
    867 
    868     if (len < 0)
    869         l = strlen((const char *) name);
    870     else
    871         l = len;
    872 
    873     if (((dict->limit > 0) && (l >= dict->limit)) ||
    874         (l > INT_MAX / 2))
    875         return(NULL);
    876 
    877     /*
    878      * Check for duplicate and insertion location.
    879      */
    880     okey = xmlDictComputeKey(dict, name, l);
    881     key = okey % dict->size;
    882     if (dict->dict[key].valid == 0) {
    883 	insert = NULL;
    884     } else {
    885 	for (insert = &(dict->dict[key]); insert->next != NULL;
    886 	     insert = insert->next) {
    887 #ifdef __GNUC__
    888 	    if ((insert->okey == okey) && (insert->len == l)) {
    889 		if (!memcmp(insert->name, name, l))
    890 		    return(insert->name);
    891 	    }
    892 #else
    893 	    if ((insert->okey == okey) && (insert->len == l) &&
    894 	        (!xmlStrncmp(insert->name, name, l)))
    895 		return(insert->name);
    896 #endif
    897 	    nbi++;
    898 	}
    899 #ifdef __GNUC__
    900 	if ((insert->okey == okey) && (insert->len == l)) {
    901 	    if (!memcmp(insert->name, name, l))
    902 		return(insert->name);
    903 	}
    904 #else
    905 	if ((insert->okey == okey) && (insert->len == l) &&
    906 	    (!xmlStrncmp(insert->name, name, l)))
    907 	    return(insert->name);
    908 #endif
    909     }
    910 
    911     if (dict->subdict) {
    912         unsigned long skey;
    913 
    914         /* we cannot always reuse the same okey for the subdict */
    915         if (((dict->size == MIN_DICT_SIZE) &&
    916 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
    917             ((dict->size != MIN_DICT_SIZE) &&
    918 	     (dict->subdict->size == MIN_DICT_SIZE)))
    919 	    skey = xmlDictComputeKey(dict->subdict, name, l);
    920 	else
    921 	    skey = okey;
    922 
    923 	key = skey % dict->subdict->size;
    924 	if (dict->subdict->dict[key].valid != 0) {
    925 	    xmlDictEntryPtr tmp;
    926 
    927 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
    928 		 tmp = tmp->next) {
    929 #ifdef __GNUC__
    930 		if ((tmp->okey == skey) && (tmp->len == l)) {
    931 		    if (!memcmp(tmp->name, name, l))
    932 			return(tmp->name);
    933 		}
    934 #else
    935 		if ((tmp->okey == skey) && (tmp->len == l) &&
    936 		    (!xmlStrncmp(tmp->name, name, l)))
    937 		    return(tmp->name);
    938 #endif
    939 		nbi++;
    940 	    }
    941 #ifdef __GNUC__
    942 	    if ((tmp->okey == skey) && (tmp->len == l)) {
    943 		if (!memcmp(tmp->name, name, l))
    944 		    return(tmp->name);
    945 	    }
    946 #else
    947 	    if ((tmp->okey == skey) && (tmp->len == l) &&
    948 		(!xmlStrncmp(tmp->name, name, l)))
    949 		return(tmp->name);
    950 #endif
    951 	}
    952 	key = okey % dict->size;
    953     }
    954 
    955     ret = xmlDictAddString(dict, name, l);
    956     if (ret == NULL)
    957         return(NULL);
    958     if (insert == NULL) {
    959 	entry = &(dict->dict[key]);
    960     } else {
    961 	entry = xmlMalloc(sizeof(xmlDictEntry));
    962 	if (entry == NULL)
    963 	     return(NULL);
    964     }
    965     entry->name = ret;
    966     entry->len = l;
    967     entry->next = NULL;
    968     entry->valid = 1;
    969     entry->okey = okey;
    970 
    971 
    972     if (insert != NULL)
    973 	insert->next = entry;
    974 
    975     dict->nbElems++;
    976 
    977     if ((nbi > MAX_HASH_LEN) &&
    978         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) {
    979 	if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0)
    980 	    return(NULL);
    981     }
    982     /* Note that entry may have been freed at this point by xmlDictGrow */
    983 
    984     return(ret);
    985 }
    986 
    987 /**
    988  * xmlDictExists:
    989  * @dict: the dictionary
    990  * @name: the name of the userdata
    991  * @len: the length of the name, if -1 it is recomputed
    992  *
    993  * Check if the @name exists in the dictionary @dict.
    994  *
    995  * Returns the internal copy of the name or NULL if not found.
    996  */
    997 const xmlChar *
    998 xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
    999     unsigned long key, okey, nbi = 0;
   1000     xmlDictEntryPtr insert;
   1001     unsigned int l;
   1002 
   1003     if ((dict == NULL) || (name == NULL))
   1004 	return(NULL);
   1005 
   1006     if (len < 0)
   1007         l = strlen((const char *) name);
   1008     else
   1009         l = len;
   1010     if (((dict->limit > 0) && (l >= dict->limit)) ||
   1011         (l > INT_MAX / 2))
   1012         return(NULL);
   1013 
   1014     /*
   1015      * Check for duplicate and insertion location.
   1016      */
   1017     okey = xmlDictComputeKey(dict, name, l);
   1018     key = okey % dict->size;
   1019     if (dict->dict[key].valid == 0) {
   1020 	insert = NULL;
   1021     } else {
   1022 	for (insert = &(dict->dict[key]); insert->next != NULL;
   1023 	     insert = insert->next) {
   1024 #ifdef __GNUC__
   1025 	    if ((insert->okey == okey) && (insert->len == l)) {
   1026 		if (!memcmp(insert->name, name, l))
   1027 		    return(insert->name);
   1028 	    }
   1029 #else
   1030 	    if ((insert->okey == okey) && (insert->len == l) &&
   1031 	        (!xmlStrncmp(insert->name, name, l)))
   1032 		return(insert->name);
   1033 #endif
   1034 	    nbi++;
   1035 	}
   1036 #ifdef __GNUC__
   1037 	if ((insert->okey == okey) && (insert->len == l)) {
   1038 	    if (!memcmp(insert->name, name, l))
   1039 		return(insert->name);
   1040 	}
   1041 #else
   1042 	if ((insert->okey == okey) && (insert->len == l) &&
   1043 	    (!xmlStrncmp(insert->name, name, l)))
   1044 	    return(insert->name);
   1045 #endif
   1046     }
   1047 
   1048     if (dict->subdict) {
   1049         unsigned long skey;
   1050 
   1051         /* we cannot always reuse the same okey for the subdict */
   1052         if (((dict->size == MIN_DICT_SIZE) &&
   1053 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
   1054             ((dict->size != MIN_DICT_SIZE) &&
   1055 	     (dict->subdict->size == MIN_DICT_SIZE)))
   1056 	    skey = xmlDictComputeKey(dict->subdict, name, l);
   1057 	else
   1058 	    skey = okey;
   1059 
   1060 	key = skey % dict->subdict->size;
   1061 	if (dict->subdict->dict[key].valid != 0) {
   1062 	    xmlDictEntryPtr tmp;
   1063 
   1064 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
   1065 		 tmp = tmp->next) {
   1066 #ifdef __GNUC__
   1067 		if ((tmp->okey == skey) && (tmp->len == l)) {
   1068 		    if (!memcmp(tmp->name, name, l))
   1069 			return(tmp->name);
   1070 		}
   1071 #else
   1072 		if ((tmp->okey == skey) && (tmp->len == l) &&
   1073 		    (!xmlStrncmp(tmp->name, name, l)))
   1074 		    return(tmp->name);
   1075 #endif
   1076 		nbi++;
   1077 	    }
   1078 #ifdef __GNUC__
   1079 	    if ((tmp->okey == skey) && (tmp->len == l)) {
   1080 		if (!memcmp(tmp->name, name, l))
   1081 		    return(tmp->name);
   1082 	    }
   1083 #else
   1084 	    if ((tmp->okey == skey) && (tmp->len == l) &&
   1085 		(!xmlStrncmp(tmp->name, name, l)))
   1086 		return(tmp->name);
   1087 #endif
   1088 	}
   1089     }
   1090 
   1091     /* not found */
   1092     return(NULL);
   1093 }
   1094 
   1095 /**
   1096  * xmlDictQLookup:
   1097  * @dict: the dictionary
   1098  * @prefix: the prefix
   1099  * @name: the name
   1100  *
   1101  * Add the QName @prefix:@name to the hash @dict if not present.
   1102  *
   1103  * Returns the internal copy of the QName or NULL in case of internal error
   1104  */
   1105 const xmlChar *
   1106 xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
   1107     unsigned long okey, key, nbi = 0;
   1108     xmlDictEntryPtr entry;
   1109     xmlDictEntryPtr insert;
   1110     const xmlChar *ret;
   1111     unsigned int len, plen, l;
   1112 
   1113     if ((dict == NULL) || (name == NULL))
   1114 	return(NULL);
   1115     if (prefix == NULL)
   1116         return(xmlDictLookup(dict, name, -1));
   1117 
   1118     l = len = strlen((const char *) name);
   1119     plen = strlen((const char *) prefix);
   1120     len += 1 + plen;
   1121 
   1122     /*
   1123      * Check for duplicate and insertion location.
   1124      */
   1125     okey = xmlDictComputeQKey(dict, prefix, plen, name, l);
   1126     key = okey % dict->size;
   1127     if (dict->dict[key].valid == 0) {
   1128 	insert = NULL;
   1129     } else {
   1130 	for (insert = &(dict->dict[key]); insert->next != NULL;
   1131 	     insert = insert->next) {
   1132 	    if ((insert->okey == okey) && (insert->len == len) &&
   1133 	        (xmlStrQEqual(prefix, name, insert->name)))
   1134 		return(insert->name);
   1135 	    nbi++;
   1136 	}
   1137 	if ((insert->okey == okey) && (insert->len == len) &&
   1138 	    (xmlStrQEqual(prefix, name, insert->name)))
   1139 	    return(insert->name);
   1140     }
   1141 
   1142     if (dict->subdict) {
   1143         unsigned long skey;
   1144 
   1145         /* we cannot always reuse the same okey for the subdict */
   1146         if (((dict->size == MIN_DICT_SIZE) &&
   1147 	     (dict->subdict->size != MIN_DICT_SIZE)) ||
   1148             ((dict->size != MIN_DICT_SIZE) &&
   1149 	     (dict->subdict->size == MIN_DICT_SIZE)))
   1150 	    skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l);
   1151 	else
   1152 	    skey = okey;
   1153 
   1154 	key = skey % dict->subdict->size;
   1155 	if (dict->subdict->dict[key].valid != 0) {
   1156 	    xmlDictEntryPtr tmp;
   1157 	    for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL;
   1158 		 tmp = tmp->next) {
   1159 		if ((tmp->okey == skey) && (tmp->len == len) &&
   1160 		    (xmlStrQEqual(prefix, name, tmp->name)))
   1161 		    return(tmp->name);
   1162 		nbi++;
   1163 	    }
   1164 	    if ((tmp->okey == skey) && (tmp->len == len) &&
   1165 		(xmlStrQEqual(prefix, name, tmp->name)))
   1166 		return(tmp->name);
   1167 	}
   1168 	key = okey % dict->size;
   1169     }
   1170 
   1171     ret = xmlDictAddQString(dict, prefix, plen, name, l);
   1172     if (ret == NULL)
   1173         return(NULL);
   1174     if (insert == NULL) {
   1175 	entry = &(dict->dict[key]);
   1176     } else {
   1177 	entry = xmlMalloc(sizeof(xmlDictEntry));
   1178 	if (entry == NULL)
   1179 	     return(NULL);
   1180     }
   1181     entry->name = ret;
   1182     entry->len = len;
   1183     entry->next = NULL;
   1184     entry->valid = 1;
   1185     entry->okey = okey;
   1186 
   1187     if (insert != NULL)
   1188 	insert->next = entry;
   1189 
   1190     dict->nbElems++;
   1191 
   1192     if ((nbi > MAX_HASH_LEN) &&
   1193         (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN)))
   1194 	xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size);
   1195     /* Note that entry may have been freed at this point by xmlDictGrow */
   1196 
   1197     return(ret);
   1198 }
   1199 
   1200 /**
   1201  * xmlDictOwns:
   1202  * @dict: the dictionary
   1203  * @str: the string
   1204  *
   1205  * check if a string is owned by the disctionary
   1206  *
   1207  * Returns 1 if true, 0 if false and -1 in case of error
   1208  * -1 in case of error
   1209  */
   1210 int
   1211 xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
   1212     xmlDictStringsPtr pool;
   1213 
   1214     if ((dict == NULL) || (str == NULL))
   1215 	return(-1);
   1216     pool = dict->strings;
   1217     while (pool != NULL) {
   1218         if ((str >= &pool->array[0]) && (str <= pool->free))
   1219 	    return(1);
   1220 	pool = pool->next;
   1221     }
   1222     if (dict->subdict)
   1223         return(xmlDictOwns(dict->subdict, str));
   1224     return(0);
   1225 }
   1226 
   1227 /**
   1228  * xmlDictSize:
   1229  * @dict: the dictionary
   1230  *
   1231  * Query the number of elements installed in the hash @dict.
   1232  *
   1233  * Returns the number of elements in the dictionary or
   1234  * -1 in case of error
   1235  */
   1236 int
   1237 xmlDictSize(xmlDictPtr dict) {
   1238     if (dict == NULL)
   1239 	return(-1);
   1240     if (dict->subdict)
   1241         return(dict->nbElems + dict->subdict->nbElems);
   1242     return(dict->nbElems);
   1243 }
   1244 
   1245 /**
   1246  * xmlDictSetLimit:
   1247  * @dict: the dictionary
   1248  * @limit: the limit in bytes
   1249  *
   1250  * Set a size limit for the dictionary
   1251  * Added in 2.9.0
   1252  *
   1253  * Returns the previous limit of the dictionary or 0
   1254  */
   1255 size_t
   1256 xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
   1257     size_t ret;
   1258 
   1259     if (dict == NULL)
   1260 	return(0);
   1261     ret = dict->limit;
   1262     dict->limit = limit;
   1263     return(ret);
   1264 }
   1265 
   1266 /**
   1267  * xmlDictGetUsage:
   1268  * @dict: the dictionary
   1269  *
   1270  * Get how much memory is used by a dictionary for strings
   1271  * Added in 2.9.0
   1272  *
   1273  * Returns the amount of strings allocated
   1274  */
   1275 size_t
   1276 xmlDictGetUsage(xmlDictPtr dict) {
   1277     xmlDictStringsPtr pool;
   1278     size_t limit = 0;
   1279 
   1280     if (dict == NULL)
   1281 	return(0);
   1282     pool = dict->strings;
   1283     while (pool != NULL) {
   1284         limit += pool->size;
   1285 	pool = pool->next;
   1286     }
   1287     return(limit);
   1288 }
   1289 
   1290 #define bottom_dict
   1291 #include "elfgcchack.h"
   1292