dict.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  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. #include <string.h>
  22. #include <time.h>
  23. #include "private/dict.h"
  24. #include "private/threads.h"
  25. #include <libxml/parser.h>
  26. #include <libxml/dict.h>
  27. #include <libxml/xmlmemory.h>
  28. #include <libxml/xmlstring.h>
  29. #ifndef SIZE_MAX
  30. #define SIZE_MAX ((size_t) -1)
  31. #endif
  32. #define MAX_FILL_NUM 7
  33. #define MAX_FILL_DENOM 8
  34. #define MIN_HASH_SIZE 8
  35. #define MAX_HASH_SIZE (1u << 31)
  36. typedef struct _xmlDictStrings xmlDictStrings;
  37. typedef xmlDictStrings *xmlDictStringsPtr;
  38. struct _xmlDictStrings {
  39. xmlDictStringsPtr next;
  40. xmlChar *free;
  41. xmlChar *end;
  42. size_t size;
  43. size_t nbStrings;
  44. xmlChar array[1];
  45. };
  46. typedef xmlHashedString xmlDictEntry;
  47. /*
  48. * The entire dictionary
  49. */
  50. struct _xmlDict {
  51. int ref_counter;
  52. xmlDictEntry *table;
  53. size_t size;
  54. unsigned int nbElems;
  55. xmlDictStringsPtr strings;
  56. struct _xmlDict *subdict;
  57. /* used for randomization */
  58. unsigned seed;
  59. /* used to impose a limit on size */
  60. size_t limit;
  61. };
  62. /*
  63. * A mutex for modifying the reference counter for shared
  64. * dictionaries.
  65. */
  66. static xmlMutex xmlDictMutex;
  67. /**
  68. * xmlInitializeDict:
  69. *
  70. * DEPRECATED: Alias for xmlInitParser.
  71. *
  72. * Returns 0.
  73. */
  74. int
  75. xmlInitializeDict(void) {
  76. xmlInitParser();
  77. return(0);
  78. }
  79. /**
  80. * xmlInitDictInternal:
  81. *
  82. * Initialize mutex.
  83. */
  84. void
  85. xmlInitDictInternal(void) {
  86. xmlInitMutex(&xmlDictMutex);
  87. }
  88. /**
  89. * xmlDictCleanup:
  90. *
  91. * DEPRECATED: This function is a no-op. Call xmlCleanupParser
  92. * to free global state but see the warnings there. xmlCleanupParser
  93. * should be only called once at program exit. In most cases, you don't
  94. * have call cleanup functions at all.
  95. */
  96. void
  97. xmlDictCleanup(void) {
  98. }
  99. /**
  100. * xmlCleanupDictInternal:
  101. *
  102. * Free the dictionary mutex.
  103. */
  104. void
  105. xmlCleanupDictInternal(void) {
  106. xmlCleanupMutex(&xmlDictMutex);
  107. }
  108. /*
  109. * xmlDictAddString:
  110. * @dict: the dictionary
  111. * @name: the name of the userdata
  112. * @len: the length of the name
  113. *
  114. * Add the string to the array[s]
  115. *
  116. * Returns the pointer of the local string, or NULL in case of error.
  117. */
  118. static const xmlChar *
  119. xmlDictAddString(xmlDictPtr dict, const xmlChar *name, unsigned int namelen) {
  120. xmlDictStringsPtr pool;
  121. const xmlChar *ret;
  122. size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
  123. size_t limit = 0;
  124. pool = dict->strings;
  125. while (pool != NULL) {
  126. if ((size_t)(pool->end - pool->free) > namelen)
  127. goto found_pool;
  128. if (pool->size > size) size = pool->size;
  129. limit += pool->size;
  130. pool = pool->next;
  131. }
  132. /*
  133. * Not found, need to allocate
  134. */
  135. if (pool == NULL) {
  136. if ((dict->limit > 0) && (limit > dict->limit)) {
  137. return(NULL);
  138. }
  139. if (size == 0) {
  140. size = 1000;
  141. } else {
  142. if (size < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
  143. size *= 4; /* exponential growth */
  144. else
  145. size = SIZE_MAX - sizeof(xmlDictStrings);
  146. }
  147. if (size / 4 < namelen) {
  148. if ((size_t) namelen + 0 < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
  149. size = 4 * (size_t) namelen; /* just in case ! */
  150. else
  151. return(NULL);
  152. }
  153. pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
  154. if (pool == NULL)
  155. return(NULL);
  156. pool->size = size;
  157. pool->nbStrings = 0;
  158. pool->free = &pool->array[0];
  159. pool->end = &pool->array[size];
  160. pool->next = dict->strings;
  161. dict->strings = pool;
  162. }
  163. found_pool:
  164. ret = pool->free;
  165. memcpy(pool->free, name, namelen);
  166. pool->free += namelen;
  167. *(pool->free++) = 0;
  168. pool->nbStrings++;
  169. return(ret);
  170. }
  171. /*
  172. * xmlDictAddQString:
  173. * @dict: the dictionary
  174. * @prefix: the prefix of the userdata
  175. * @plen: the prefix length
  176. * @name: the name of the userdata
  177. * @len: the length of the name
  178. *
  179. * Add the QName to the array[s]
  180. *
  181. * Returns the pointer of the local string, or NULL in case of error.
  182. */
  183. static const xmlChar *
  184. xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, unsigned int plen,
  185. const xmlChar *name, unsigned int namelen)
  186. {
  187. xmlDictStringsPtr pool;
  188. const xmlChar *ret;
  189. size_t size = 0; /* + sizeof(_xmlDictStrings) == 1024 */
  190. size_t limit = 0;
  191. pool = dict->strings;
  192. while (pool != NULL) {
  193. if ((size_t)(pool->end - pool->free) > namelen + plen + 1)
  194. goto found_pool;
  195. if (pool->size > size) size = pool->size;
  196. limit += pool->size;
  197. pool = pool->next;
  198. }
  199. /*
  200. * Not found, need to allocate
  201. */
  202. if (pool == NULL) {
  203. if ((dict->limit > 0) && (limit > dict->limit)) {
  204. return(NULL);
  205. }
  206. if (size == 0) size = 1000;
  207. else size *= 4; /* exponential growth */
  208. if (size < 4 * (namelen + plen + 1))
  209. size = 4 * (namelen + plen + 1); /* just in case ! */
  210. pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
  211. if (pool == NULL)
  212. return(NULL);
  213. pool->size = size;
  214. pool->nbStrings = 0;
  215. pool->free = &pool->array[0];
  216. pool->end = &pool->array[size];
  217. pool->next = dict->strings;
  218. dict->strings = pool;
  219. }
  220. found_pool:
  221. ret = pool->free;
  222. memcpy(pool->free, prefix, plen);
  223. pool->free += plen;
  224. *(pool->free++) = ':';
  225. memcpy(pool->free, name, namelen);
  226. pool->free += namelen;
  227. *(pool->free++) = 0;
  228. pool->nbStrings++;
  229. return(ret);
  230. }
  231. /**
  232. * xmlDictCreate:
  233. *
  234. * Create a new dictionary
  235. *
  236. * Returns the newly created dictionary, or NULL if an error occurred.
  237. */
  238. xmlDictPtr
  239. xmlDictCreate(void) {
  240. xmlDictPtr dict;
  241. xmlInitParser();
  242. dict = xmlMalloc(sizeof(xmlDict));
  243. if (dict == NULL)
  244. return(NULL);
  245. dict->ref_counter = 1;
  246. dict->limit = 0;
  247. dict->size = 0;
  248. dict->nbElems = 0;
  249. dict->table = NULL;
  250. dict->strings = NULL;
  251. dict->subdict = NULL;
  252. dict->seed = xmlRandom();
  253. #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  254. dict->seed = 0;
  255. #endif
  256. return(dict);
  257. }
  258. /**
  259. * xmlDictCreateSub:
  260. * @sub: an existing dictionary
  261. *
  262. * Create a new dictionary, inheriting strings from the read-only
  263. * dictionary @sub. On lookup, strings are first searched in the
  264. * new dictionary, then in @sub, and if not found are created in the
  265. * new dictionary.
  266. *
  267. * Returns the newly created dictionary, or NULL if an error occurred.
  268. */
  269. xmlDictPtr
  270. xmlDictCreateSub(xmlDictPtr sub) {
  271. xmlDictPtr dict = xmlDictCreate();
  272. if ((dict != NULL) && (sub != NULL)) {
  273. dict->seed = sub->seed;
  274. dict->subdict = sub;
  275. xmlDictReference(dict->subdict);
  276. }
  277. return(dict);
  278. }
  279. /**
  280. * xmlDictReference:
  281. * @dict: the dictionary
  282. *
  283. * Increment the reference counter of a dictionary
  284. *
  285. * Returns 0 in case of success and -1 in case of error
  286. */
  287. int
  288. xmlDictReference(xmlDictPtr dict) {
  289. if (dict == NULL) return -1;
  290. xmlMutexLock(&xmlDictMutex);
  291. dict->ref_counter++;
  292. xmlMutexUnlock(&xmlDictMutex);
  293. return(0);
  294. }
  295. /**
  296. * xmlDictFree:
  297. * @dict: the dictionary
  298. *
  299. * Free the hash @dict and its contents. The userdata is
  300. * deallocated with @f if provided.
  301. */
  302. void
  303. xmlDictFree(xmlDictPtr dict) {
  304. xmlDictStringsPtr pool, nextp;
  305. if (dict == NULL)
  306. return;
  307. /* decrement the counter, it may be shared by a parser and docs */
  308. xmlMutexLock(&xmlDictMutex);
  309. dict->ref_counter--;
  310. if (dict->ref_counter > 0) {
  311. xmlMutexUnlock(&xmlDictMutex);
  312. return;
  313. }
  314. xmlMutexUnlock(&xmlDictMutex);
  315. if (dict->subdict != NULL) {
  316. xmlDictFree(dict->subdict);
  317. }
  318. if (dict->table) {
  319. xmlFree(dict->table);
  320. }
  321. pool = dict->strings;
  322. while (pool != NULL) {
  323. nextp = pool->next;
  324. xmlFree(pool);
  325. pool = nextp;
  326. }
  327. xmlFree(dict);
  328. }
  329. /**
  330. * xmlDictOwns:
  331. * @dict: the dictionary
  332. * @str: the string
  333. *
  334. * check if a string is owned by the dictionary
  335. *
  336. * Returns 1 if true, 0 if false and -1 in case of error
  337. * -1 in case of error
  338. */
  339. int
  340. xmlDictOwns(xmlDictPtr dict, const xmlChar *str) {
  341. xmlDictStringsPtr pool;
  342. if ((dict == NULL) || (str == NULL))
  343. return(-1);
  344. pool = dict->strings;
  345. while (pool != NULL) {
  346. if ((str >= &pool->array[0]) && (str <= pool->free))
  347. return(1);
  348. pool = pool->next;
  349. }
  350. if (dict->subdict)
  351. return(xmlDictOwns(dict->subdict, str));
  352. return(0);
  353. }
  354. /**
  355. * xmlDictSize:
  356. * @dict: the dictionary
  357. *
  358. * Query the number of elements installed in the hash @dict.
  359. *
  360. * Returns the number of elements in the dictionary or
  361. * -1 in case of error
  362. */
  363. int
  364. xmlDictSize(xmlDictPtr dict) {
  365. if (dict == NULL)
  366. return(-1);
  367. if (dict->subdict)
  368. return(dict->nbElems + dict->subdict->nbElems);
  369. return(dict->nbElems);
  370. }
  371. /**
  372. * xmlDictSetLimit:
  373. * @dict: the dictionary
  374. * @limit: the limit in bytes
  375. *
  376. * Set a size limit for the dictionary
  377. * Added in 2.9.0
  378. *
  379. * Returns the previous limit of the dictionary or 0
  380. */
  381. size_t
  382. xmlDictSetLimit(xmlDictPtr dict, size_t limit) {
  383. size_t ret;
  384. if (dict == NULL)
  385. return(0);
  386. ret = dict->limit;
  387. dict->limit = limit;
  388. return(ret);
  389. }
  390. /**
  391. * xmlDictGetUsage:
  392. * @dict: the dictionary
  393. *
  394. * Get how much memory is used by a dictionary for strings
  395. * Added in 2.9.0
  396. *
  397. * Returns the amount of strings allocated
  398. */
  399. size_t
  400. xmlDictGetUsage(xmlDictPtr dict) {
  401. xmlDictStringsPtr pool;
  402. size_t limit = 0;
  403. if (dict == NULL)
  404. return(0);
  405. pool = dict->strings;
  406. while (pool != NULL) {
  407. limit += pool->size;
  408. pool = pool->next;
  409. }
  410. return(limit);
  411. }
  412. /*****************************************************************
  413. *
  414. * The code below was rewritten and is additionally licensed under
  415. * the main license in file 'Copyright'.
  416. *
  417. *****************************************************************/
  418. ATTRIBUTE_NO_SANITIZE_INTEGER
  419. static unsigned
  420. xmlDictHashName(unsigned seed, const xmlChar* data, size_t maxLen,
  421. size_t *plen) {
  422. unsigned h1, h2;
  423. size_t i;
  424. HASH_INIT(h1, h2, seed);
  425. for (i = 0; i < maxLen && data[i]; i++) {
  426. HASH_UPDATE(h1, h2, data[i]);
  427. }
  428. HASH_FINISH(h1, h2);
  429. *plen = i;
  430. return(h2 | MAX_HASH_SIZE);
  431. }
  432. ATTRIBUTE_NO_SANITIZE_INTEGER
  433. static unsigned
  434. xmlDictHashQName(unsigned seed, const xmlChar *prefix, const xmlChar *name,
  435. size_t *pplen, size_t *plen) {
  436. unsigned h1, h2;
  437. size_t i;
  438. HASH_INIT(h1, h2, seed);
  439. for (i = 0; prefix[i] != 0; i++) {
  440. HASH_UPDATE(h1, h2, prefix[i]);
  441. }
  442. *pplen = i;
  443. HASH_UPDATE(h1, h2, ':');
  444. for (i = 0; name[i] != 0; i++) {
  445. HASH_UPDATE(h1, h2, name[i]);
  446. }
  447. *plen = i;
  448. HASH_FINISH(h1, h2);
  449. /*
  450. * Always set the upper bit of hash values since 0 means an unoccupied
  451. * bucket.
  452. */
  453. return(h2 | MAX_HASH_SIZE);
  454. }
  455. unsigned
  456. xmlDictComputeHash(const xmlDict *dict, const xmlChar *string) {
  457. size_t len;
  458. return(xmlDictHashName(dict->seed, string, SIZE_MAX, &len));
  459. }
  460. #define HASH_ROL31(x,n) ((x) << (n) | ((x) & 0x7FFFFFFF) >> (31 - (n)))
  461. ATTRIBUTE_NO_SANITIZE_INTEGER
  462. unsigned
  463. xmlDictCombineHash(unsigned v1, unsigned v2) {
  464. /*
  465. * The upper bit of hash values is always set, so we have to operate on
  466. * 31-bit hashes here.
  467. */
  468. v1 ^= v2;
  469. v1 += HASH_ROL31(v2, 5);
  470. return((v1 & 0xFFFFFFFF) | 0x80000000);
  471. }
  472. /**
  473. * xmlDictFindEntry:
  474. * @dict: dict
  475. * @prefix: optional QName prefix
  476. * @name: string
  477. * @len: length of string
  478. * @hashValue: valid hash value of string
  479. * @pfound: result of search
  480. *
  481. * Try to find a matching hash table entry. If an entry was found, set
  482. * @found to 1 and return the entry. Otherwise, set @found to 0 and return
  483. * the location where a new entry should be inserted.
  484. */
  485. ATTRIBUTE_NO_SANITIZE_INTEGER
  486. static xmlDictEntry *
  487. xmlDictFindEntry(const xmlDict *dict, const xmlChar *prefix,
  488. const xmlChar *name, int len, unsigned hashValue,
  489. int *pfound) {
  490. xmlDictEntry *entry;
  491. unsigned mask, pos, displ;
  492. int found = 0;
  493. mask = dict->size - 1;
  494. pos = hashValue & mask;
  495. entry = &dict->table[pos];
  496. if (entry->hashValue != 0) {
  497. /*
  498. * Robin hood hashing: abort if the displacement of the entry
  499. * is smaller than the displacement of the key we look for.
  500. * This also stops at the correct position when inserting.
  501. */
  502. displ = 0;
  503. do {
  504. if (entry->hashValue == hashValue) {
  505. if (prefix == NULL) {
  506. /*
  507. * name is not necessarily null-terminated.
  508. */
  509. if ((strncmp((const char *) entry->name,
  510. (const char *) name, len) == 0) &&
  511. (entry->name[len] == 0)) {
  512. found = 1;
  513. break;
  514. }
  515. } else {
  516. if (xmlStrQEqual(prefix, name, entry->name)) {
  517. found = 1;
  518. break;
  519. }
  520. }
  521. }
  522. displ++;
  523. pos++;
  524. entry++;
  525. if ((pos & mask) == 0)
  526. entry = dict->table;
  527. } while ((entry->hashValue != 0) &&
  528. (((pos - entry->hashValue) & mask) >= displ));
  529. }
  530. *pfound = found;
  531. return(entry);
  532. }
  533. /**
  534. * xmlDictGrow:
  535. * @dict: dictionary
  536. * @size: new size of the dictionary
  537. *
  538. * Resize the dictionary hash table.
  539. *
  540. * Returns 0 in case of success, -1 if a memory allocation failed.
  541. */
  542. static int
  543. xmlDictGrow(xmlDictPtr dict, unsigned size) {
  544. const xmlDictEntry *oldentry, *oldend, *end;
  545. xmlDictEntry *table;
  546. unsigned oldsize, i;
  547. /* Add 0 to avoid spurious -Wtype-limits warning on 64-bit GCC */
  548. if ((size_t) size + 0 > SIZE_MAX / sizeof(table[0]))
  549. return(-1);
  550. table = xmlMalloc(size * sizeof(table[0]));
  551. if (table == NULL)
  552. return(-1);
  553. memset(table, 0, size * sizeof(table[0]));
  554. oldsize = dict->size;
  555. if (oldsize == 0)
  556. goto done;
  557. oldend = &dict->table[oldsize];
  558. end = &table[size];
  559. /*
  560. * Robin Hood sorting order is maintained if we
  561. *
  562. * - compute dict indices with modulo
  563. * - resize by an integer factor
  564. * - start to copy from the beginning of a probe sequence
  565. */
  566. oldentry = dict->table;
  567. while (oldentry->hashValue != 0) {
  568. if (++oldentry >= oldend)
  569. oldentry = dict->table;
  570. }
  571. for (i = 0; i < oldsize; i++) {
  572. if (oldentry->hashValue != 0) {
  573. xmlDictEntry *entry = &table[oldentry->hashValue & (size - 1)];
  574. while (entry->hashValue != 0) {
  575. if (++entry >= end)
  576. entry = table;
  577. }
  578. *entry = *oldentry;
  579. }
  580. if (++oldentry >= oldend)
  581. oldentry = dict->table;
  582. }
  583. xmlFree(dict->table);
  584. done:
  585. dict->table = table;
  586. dict->size = size;
  587. return(0);
  588. }
  589. /**
  590. * xmlDictLookupInternal:
  591. * @dict: dict
  592. * @prefix: optional QName prefix
  593. * @name: string
  594. * @maybeLen: length of string or -1 if unknown
  595. * @update: whether the string should be added
  596. *
  597. * Internal lookup and update function.
  598. */
  599. ATTRIBUTE_NO_SANITIZE_INTEGER
  600. static const xmlDictEntry *
  601. xmlDictLookupInternal(xmlDictPtr dict, const xmlChar *prefix,
  602. const xmlChar *name, int maybeLen, int update) {
  603. xmlDictEntry *entry = NULL;
  604. const xmlChar *ret;
  605. unsigned hashValue;
  606. size_t maxLen, len, plen, klen;
  607. int found = 0;
  608. if ((dict == NULL) || (name == NULL))
  609. return(NULL);
  610. maxLen = (maybeLen < 0) ? SIZE_MAX : (size_t) maybeLen;
  611. if (prefix == NULL) {
  612. hashValue = xmlDictHashName(dict->seed, name, maxLen, &len);
  613. if (len > INT_MAX / 2)
  614. return(NULL);
  615. klen = len;
  616. } else {
  617. hashValue = xmlDictHashQName(dict->seed, prefix, name, &plen, &len);
  618. if ((len > INT_MAX / 2) || (plen >= INT_MAX / 2 - len))
  619. return(NULL);
  620. klen = plen + 1 + len;
  621. }
  622. if ((dict->limit > 0) && (klen >= dict->limit))
  623. return(NULL);
  624. /*
  625. * Check for an existing entry
  626. */
  627. if (dict->size > 0)
  628. entry = xmlDictFindEntry(dict, prefix, name, klen, hashValue, &found);
  629. if (found)
  630. return(entry);
  631. if ((dict->subdict != NULL) && (dict->subdict->size > 0)) {
  632. xmlDictEntry *subEntry;
  633. unsigned subHashValue;
  634. if (prefix == NULL)
  635. subHashValue = xmlDictHashName(dict->subdict->seed, name, len,
  636. &len);
  637. else
  638. subHashValue = xmlDictHashQName(dict->subdict->seed, prefix, name,
  639. &plen, &len);
  640. subEntry = xmlDictFindEntry(dict->subdict, prefix, name, klen,
  641. subHashValue, &found);
  642. if (found)
  643. return(subEntry);
  644. }
  645. if (!update)
  646. return(NULL);
  647. /*
  648. * Grow the hash table if needed
  649. */
  650. if (dict->nbElems + 1 > dict->size / MAX_FILL_DENOM * MAX_FILL_NUM) {
  651. unsigned newSize, mask, displ, pos;
  652. if (dict->size == 0) {
  653. newSize = MIN_HASH_SIZE;
  654. } else {
  655. if (dict->size >= MAX_HASH_SIZE)
  656. return(NULL);
  657. newSize = dict->size * 2;
  658. }
  659. if (xmlDictGrow(dict, newSize) != 0)
  660. return(NULL);
  661. /*
  662. * Find new entry
  663. */
  664. mask = dict->size - 1;
  665. displ = 0;
  666. pos = hashValue & mask;
  667. entry = &dict->table[pos];
  668. while ((entry->hashValue != 0) &&
  669. ((pos - entry->hashValue) & mask) >= displ) {
  670. displ++;
  671. pos++;
  672. entry++;
  673. if ((pos & mask) == 0)
  674. entry = dict->table;
  675. }
  676. }
  677. if (prefix == NULL)
  678. ret = xmlDictAddString(dict, name, len);
  679. else
  680. ret = xmlDictAddQString(dict, prefix, plen, name, len);
  681. if (ret == NULL)
  682. return(NULL);
  683. /*
  684. * Shift the remainder of the probe sequence to the right
  685. */
  686. if (entry->hashValue != 0) {
  687. const xmlDictEntry *end = &dict->table[dict->size];
  688. const xmlDictEntry *cur = entry;
  689. do {
  690. cur++;
  691. if (cur >= end)
  692. cur = dict->table;
  693. } while (cur->hashValue != 0);
  694. if (cur < entry) {
  695. /*
  696. * If we traversed the end of the buffer, handle the part
  697. * at the start of the buffer.
  698. */
  699. memmove(&dict->table[1], dict->table,
  700. (char *) cur - (char *) dict->table);
  701. cur = end - 1;
  702. dict->table[0] = *cur;
  703. }
  704. memmove(&entry[1], entry, (char *) cur - (char *) entry);
  705. }
  706. /*
  707. * Populate entry
  708. */
  709. entry->hashValue = hashValue;
  710. entry->name = ret;
  711. dict->nbElems++;
  712. return(entry);
  713. }
  714. /**
  715. * xmlDictLookup:
  716. * @dict: dictionary
  717. * @name: string key
  718. * @len: length of the key, if -1 it is recomputed
  719. *
  720. * Lookup a string and add it to the dictionary if it wasn't found.
  721. *
  722. * Returns the interned copy of the string or NULL if a memory allocation
  723. * failed.
  724. */
  725. const xmlChar *
  726. xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) {
  727. const xmlDictEntry *entry;
  728. entry = xmlDictLookupInternal(dict, NULL, name, len, 1);
  729. if (entry == NULL)
  730. return(NULL);
  731. return(entry->name);
  732. }
  733. /**
  734. * xmlDictLookupHashed:
  735. * @dict: dictionary
  736. * @name: string key
  737. * @len: length of the key, if -1 it is recomputed
  738. *
  739. * Lookup a dictionary entry and add the string to the dictionary if
  740. * it wasn't found.
  741. *
  742. * Returns the dictionary entry.
  743. */
  744. xmlHashedString
  745. xmlDictLookupHashed(xmlDictPtr dict, const xmlChar *name, int len) {
  746. const xmlDictEntry *entry;
  747. xmlHashedString ret;
  748. entry = xmlDictLookupInternal(dict, NULL, name, len, 1);
  749. if (entry == NULL) {
  750. ret.name = NULL;
  751. ret.hashValue = 0;
  752. } else {
  753. ret = *entry;
  754. }
  755. return(ret);
  756. }
  757. /**
  758. * xmlDictExists:
  759. * @dict: the dictionary
  760. * @name: the name of the userdata
  761. * @len: the length of the name, if -1 it is recomputed
  762. *
  763. * Check if a string exists in the dictionary.
  764. *
  765. * Returns the internal copy of the name or NULL if not found.
  766. */
  767. const xmlChar *
  768. xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) {
  769. const xmlDictEntry *entry;
  770. entry = xmlDictLookupInternal(dict, NULL, name, len, 0);
  771. if (entry == NULL)
  772. return(NULL);
  773. return(entry->name);
  774. }
  775. /**
  776. * xmlDictQLookup:
  777. * @dict: the dictionary
  778. * @prefix: the prefix
  779. * @name: the name
  780. *
  781. * Lookup the QName @prefix:@name and add it to the dictionary if
  782. * it wasn't found.
  783. *
  784. * Returns the interned copy of the string or NULL if a memory allocation
  785. * failed.
  786. */
  787. const xmlChar *
  788. xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
  789. const xmlDictEntry *entry;
  790. entry = xmlDictLookupInternal(dict, prefix, name, -1, 1);
  791. if (entry == NULL)
  792. return(NULL);
  793. return(entry->name);
  794. }
  795. /*
  796. * Pseudo-random generator
  797. */
  798. static xmlMutex xmlRngMutex;
  799. static unsigned globalRngState[2];
  800. #ifdef XML_THREAD_LOCAL
  801. static XML_THREAD_LOCAL int localRngInitialized = 0;
  802. static XML_THREAD_LOCAL unsigned localRngState[2];
  803. #endif
  804. ATTRIBUTE_NO_SANITIZE_INTEGER
  805. void
  806. xmlInitRandom(void) {
  807. int var;
  808. xmlInitMutex(&xmlRngMutex);
  809. /* TODO: Get seed values from system PRNG */
  810. globalRngState[0] = (unsigned) time(NULL) ^
  811. HASH_ROL((unsigned) (size_t) &xmlInitRandom, 8);
  812. globalRngState[1] = HASH_ROL((unsigned) (size_t) &xmlRngMutex, 16) ^
  813. HASH_ROL((unsigned) (size_t) &var, 24);
  814. }
  815. void
  816. xmlCleanupRandom(void) {
  817. xmlCleanupMutex(&xmlRngMutex);
  818. }
  819. ATTRIBUTE_NO_SANITIZE_INTEGER
  820. static unsigned
  821. xoroshiro64ss(unsigned *s) {
  822. unsigned s0 = s[0];
  823. unsigned s1 = s[1];
  824. unsigned result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5;
  825. s1 ^= s0;
  826. s[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9);
  827. s[1] = HASH_ROL(s1, 13);
  828. return(result & 0xFFFFFFFF);
  829. }
  830. unsigned
  831. xmlRandom(void) {
  832. #ifdef XML_THREAD_LOCAL
  833. if (!localRngInitialized) {
  834. xmlMutexLock(&xmlRngMutex);
  835. localRngState[0] = xoroshiro64ss(globalRngState);
  836. localRngState[1] = xoroshiro64ss(globalRngState);
  837. localRngInitialized = 1;
  838. xmlMutexUnlock(&xmlRngMutex);
  839. }
  840. return(xoroshiro64ss(localRngState));
  841. #else
  842. unsigned ret;
  843. xmlMutexLock(&xmlRngMutex);
  844. ret = xoroshiro64ss(globalRngState);
  845. xmlMutexUnlock(&xmlRngMutex);
  846. return(ret);
  847. #endif
  848. }