dict.c 31 KB

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