PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/lscript/lscript_library/lscript_alloc.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1136 lines | 896 code | 125 blank | 115 comment | 126 complexity | f1ad81d7e9153cf910aff60510d02839 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lscript_alloc.cpp
  3. * @brief general heap management for scripting system
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. // #define at top of file accelerates gcc compiles
  27. // Under gcc 2.9, the manual is unclear if comments can appear above #ifndef
  28. // Under gcc 3, the manual explicitly states comments can appear above the #ifndef
  29. #include "linden_common.h"
  30. #include "lscript_alloc.h"
  31. #include "llrand.h"
  32. // supported data types
  33. // basic types
  34. // integer 4 bytes of integer data
  35. // float 4 bytes of float data
  36. // string data null terminated 1 byte string
  37. // key data null terminated 1 byte string
  38. // vector data 12 bytes of 3 floats
  39. // quaternion data 16 bytes of 4 floats
  40. // list type
  41. // list data 4 bytes of number of entries followed by pointer
  42. // string pointer 4 bytes of address of string data on the heap (only used in list data)
  43. // key pointer 4 bytes of address of key data on the heap (only used in list data)
  44. // heap format
  45. //
  46. // 4 byte offset to next block (in bytes)
  47. // 1 byte of type of variable or empty
  48. // 2 bytes of reference count
  49. // nn bytes of data
  50. void reset_hp_to_safe_spot(const U8 *buffer)
  51. {
  52. set_register((U8 *)buffer, LREG_HP, TOP_OF_MEMORY);
  53. }
  54. // create a heap from the HR to TM
  55. BOOL lsa_create_heap(U8 *heap_start, S32 size)
  56. {
  57. LLScriptAllocEntry entry(size, LST_NULL);
  58. S32 position = 0;
  59. alloc_entry2bytestream(heap_start, position, entry);
  60. return TRUE;
  61. }
  62. S32 lsa_heap_top(U8 *heap_start, S32 maxtop)
  63. {
  64. S32 offset = 0;
  65. LLScriptAllocEntry entry;
  66. bytestream2alloc_entry(entry, heap_start, offset);
  67. while (offset + entry.mSize < maxtop)
  68. {
  69. offset += entry.mSize;
  70. bytestream2alloc_entry(entry, heap_start, offset);
  71. }
  72. return offset + entry.mSize;
  73. }
  74. // adding to heap
  75. // if block is empty
  76. // if block is at least block size + 4 larger than data
  77. // split block
  78. // insert data into first part
  79. // return address
  80. // else
  81. // insert data into block
  82. // return address
  83. // else
  84. // if next block is >= SP
  85. // set Stack-Heap collision
  86. // return NULL
  87. // if next block is empty
  88. // merge next block with current block
  89. // go to start of algorithm
  90. // else
  91. // move to next block
  92. // go to start of algorithm
  93. S32 lsa_heap_add_data(U8 *buffer, LLScriptLibData *data, S32 heapsize, BOOL b_delete)
  94. {
  95. if (get_register(buffer, LREG_FR))
  96. return 1;
  97. LLScriptAllocEntry entry, nextentry;
  98. S32 hr = get_register(buffer, LREG_HR);
  99. S32 hp = get_register(buffer, LREG_HP);
  100. S32 current_offset, next_offset, offset = hr;
  101. S32 size = 0;
  102. switch(data->mType)
  103. {
  104. case LST_INTEGER:
  105. size = 4;
  106. break;
  107. case LST_FLOATINGPOINT:
  108. size = 4;
  109. break;
  110. case LST_KEY:
  111. // NOTE: babbage: defensive as some library calls set data to NULL
  112. size = data->mKey ? (S32)strlen(data->mKey) + 1 : 1; /*Flawfinder: ignore*/
  113. break;
  114. case LST_STRING:
  115. // NOTE: babbage: defensive as some library calls set data to NULL
  116. size = data->mString ? (S32)strlen(data->mString) + 1 : 1; /*Flawfinder: ignore*/
  117. break;
  118. case LST_LIST:
  119. // list data 4 bytes of number of entries followed by number of pointer
  120. size = 4 + 4*data->getListLength();
  121. if (data->checkForMultipleLists())
  122. {
  123. set_fault(buffer, LSRF_NESTING_LISTS);
  124. }
  125. break;
  126. case LST_VECTOR:
  127. size = 12;
  128. break;
  129. case LST_QUATERNION:
  130. size = 16;
  131. break;
  132. default:
  133. break;
  134. }
  135. current_offset = offset;
  136. bytestream2alloc_entry(entry, buffer, offset);
  137. do
  138. {
  139. hp = get_register(buffer, LREG_HP);
  140. if (!entry.mType)
  141. {
  142. if (entry.mSize >= size + SIZEOF_SCRIPT_ALLOC_ENTRY + 4)
  143. {
  144. offset = current_offset;
  145. lsa_split_block(buffer, offset, size, entry);
  146. entry.mType = data->mType;
  147. entry.mSize = size;
  148. entry.mReferenceCount = 1;
  149. offset = current_offset;
  150. alloc_entry2bytestream(buffer, offset, entry);
  151. lsa_insert_data(buffer, offset, data, entry, heapsize);
  152. hp = get_register(buffer, LREG_HP);
  153. S32 new_hp = current_offset + size + 2*SIZEOF_SCRIPT_ALLOC_ENTRY;
  154. if (new_hp >= hr + heapsize)
  155. {
  156. break;
  157. }
  158. if (new_hp > hp)
  159. {
  160. set_register(buffer, LREG_HP, new_hp);
  161. hp = get_register(buffer, LREG_HP);
  162. }
  163. if (b_delete)
  164. delete data;
  165. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  166. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  167. if (current_offset <= hp)
  168. return current_offset - hr + 1;
  169. else
  170. return hp - hr + 1;
  171. }
  172. else if (entry.mSize >= size)
  173. {
  174. entry.mType = data->mType;
  175. entry.mReferenceCount = 1;
  176. offset = current_offset;
  177. alloc_entry2bytestream(buffer, offset, entry);
  178. lsa_insert_data(buffer, offset, data, entry, heapsize);
  179. hp = get_register(buffer, LREG_HP);
  180. if (b_delete)
  181. delete data;
  182. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  183. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  184. return current_offset - hr + 1;
  185. }
  186. }
  187. offset += entry.mSize;
  188. if (offset < hr + heapsize)
  189. {
  190. next_offset = offset;
  191. bytestream2alloc_entry(nextentry, buffer, offset);
  192. if (!nextentry.mType && !entry.mType)
  193. {
  194. entry.mSize += nextentry.mSize + SIZEOF_SCRIPT_ALLOC_ENTRY;
  195. offset = current_offset;
  196. alloc_entry2bytestream(buffer, offset, entry);
  197. }
  198. else
  199. {
  200. current_offset = next_offset;
  201. entry = nextentry;
  202. }
  203. // this works whether we are bumping out or coming in
  204. S32 new_hp = current_offset + size + 2*SIZEOF_SCRIPT_ALLOC_ENTRY;
  205. // make sure we aren't about to be stupid
  206. if (new_hp >= hr + heapsize)
  207. {
  208. break;
  209. }
  210. if (new_hp > hp)
  211. {
  212. set_register(buffer, LREG_HP, new_hp);
  213. hp = get_register(buffer, LREG_HP);
  214. }
  215. }
  216. else
  217. {
  218. break;
  219. }
  220. } while (1);
  221. set_fault(buffer, LSRF_STACK_HEAP_COLLISION);
  222. reset_hp_to_safe_spot(buffer);
  223. if (b_delete)
  224. delete data;
  225. return 0;
  226. }
  227. // split block
  228. // set offset to point to new block
  229. // set offset of new block to point to original offset - block size - data size
  230. // set new block to empty
  231. // set new block reference count to 0
  232. void lsa_split_block(U8 *buffer, S32 &offset, S32 size, LLScriptAllocEntry &entry)
  233. {
  234. if (get_register(buffer, LREG_FR))
  235. return;
  236. LLScriptAllocEntry newentry;
  237. newentry.mSize = entry.mSize - SIZEOF_SCRIPT_ALLOC_ENTRY - size;
  238. entry.mSize -= newentry.mSize + SIZEOF_SCRIPT_ALLOC_ENTRY;
  239. alloc_entry2bytestream(buffer, offset, entry);
  240. S32 orig_offset = offset + size;
  241. alloc_entry2bytestream(buffer, orig_offset, newentry);
  242. }
  243. // insert data
  244. // if data is non-list type
  245. // set type to basic type, set reference count to 1, copy data, return address
  246. // else
  247. // set type to list data type, set reference count to 1
  248. // save length of list
  249. // for each list entry
  250. // insert data
  251. // return address
  252. void lsa_insert_data(U8 *buffer, S32 &offset, LLScriptLibData *data, LLScriptAllocEntry &entry, S32 heapsize)
  253. {
  254. if (get_register(buffer, LREG_FR))
  255. return;
  256. if (data->mType != LST_LIST)
  257. {
  258. switch(data->mType)
  259. {
  260. case LST_INTEGER:
  261. integer2bytestream(buffer, offset, data->mInteger);
  262. break;
  263. case LST_FLOATINGPOINT:
  264. float2bytestream(buffer, offset, data->mFP);
  265. break;
  266. case LST_KEY:
  267. char2bytestream(buffer, offset, data->mKey ? data->mKey : "");
  268. break;
  269. case LST_STRING:
  270. char2bytestream(buffer, offset, data->mString ? data->mString : "");
  271. break;
  272. case LST_VECTOR:
  273. vector2bytestream(buffer, offset, data->mVec);
  274. break;
  275. case LST_QUATERNION:
  276. quaternion2bytestream(buffer, offset, data->mQuat);
  277. break;
  278. default:
  279. break;
  280. }
  281. }
  282. else
  283. {
  284. // store length of list
  285. integer2bytestream(buffer, offset, data->getListLength());
  286. data = data->mListp;
  287. while(data)
  288. {
  289. // store entry and then store address if valid
  290. S32 address = lsa_heap_add_data(buffer, data, heapsize, FALSE);
  291. integer2bytestream(buffer, offset, address);
  292. data = data->mListp;
  293. }
  294. }
  295. }
  296. S32 lsa_create_data_block(U8 **buffer, LLScriptLibData *data, S32 base_offset)
  297. {
  298. S32 offset = 0;
  299. S32 size = 0;
  300. LLScriptAllocEntry entry;
  301. if (!data)
  302. {
  303. entry.mType = LST_NULL;
  304. entry.mReferenceCount = 0;
  305. entry.mSize = MAX_HEAP_SIZE;
  306. size = SIZEOF_SCRIPT_ALLOC_ENTRY;
  307. *buffer = new U8[size];
  308. alloc_entry2bytestream(*buffer, offset, entry);
  309. return size;
  310. }
  311. entry.mType = data->mType;
  312. entry.mReferenceCount = 1;
  313. if (data->mType != LST_LIST)
  314. {
  315. if ( (data->mType != LST_STRING)
  316. &&(data->mType != LST_KEY))
  317. {
  318. size = LSCRIPTDataSize[data->mType];
  319. }
  320. else
  321. {
  322. if (data->mType == LST_STRING)
  323. {
  324. if (data->mString)
  325. {
  326. size = (S32)strlen(data->mString) + 1; /*Flawfinder: ignore*/
  327. }
  328. else
  329. {
  330. size = 1;
  331. }
  332. }
  333. if (data->mType == LST_KEY)
  334. {
  335. if (data->mKey)
  336. {
  337. size = (S32)strlen(data->mKey) + 1; /*Flawfinder: ignore*/
  338. }
  339. else
  340. {
  341. size = 1;
  342. }
  343. }
  344. }
  345. entry.mSize = size;
  346. size += SIZEOF_SCRIPT_ALLOC_ENTRY;
  347. *buffer = new U8[size];
  348. alloc_entry2bytestream(*buffer, offset, entry);
  349. switch(data->mType)
  350. {
  351. case LST_INTEGER:
  352. integer2bytestream(*buffer, offset, data->mInteger);
  353. break;
  354. case LST_FLOATINGPOINT:
  355. float2bytestream(*buffer, offset, data->mFP);
  356. break;
  357. case LST_KEY:
  358. if (data->mKey)
  359. char2bytestream(*buffer, offset, data->mKey);
  360. else
  361. byte2bytestream(*buffer, offset, 0);
  362. break;
  363. case LST_STRING:
  364. if (data->mString)
  365. char2bytestream(*buffer, offset, data->mString);
  366. else
  367. byte2bytestream(*buffer, offset, 0);
  368. break;
  369. case LST_VECTOR:
  370. vector2bytestream(*buffer, offset, data->mVec);
  371. break;
  372. case LST_QUATERNION:
  373. quaternion2bytestream(*buffer, offset, data->mQuat);
  374. break;
  375. default:
  376. break;
  377. }
  378. }
  379. else
  380. {
  381. U8 *listbuf;
  382. S32 length = data->getListLength();
  383. size = 4 * length + 4;
  384. entry.mSize = size;
  385. size += SIZEOF_SCRIPT_ALLOC_ENTRY;
  386. *buffer = new U8[size];
  387. alloc_entry2bytestream(*buffer, offset, entry);
  388. // store length of list
  389. integer2bytestream(*buffer, offset, length);
  390. data = data->mListp;
  391. while(data)
  392. {
  393. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  394. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  395. integer2bytestream(*buffer, offset, size + base_offset + 1);
  396. S32 listsize = lsa_create_data_block(&listbuf, data, base_offset + size);
  397. if (listsize)
  398. {
  399. U8 *tbuff = new U8[size + listsize];
  400. if (tbuff == NULL)
  401. {
  402. llerrs << "Memory Allocation Failed" << llendl;
  403. }
  404. memcpy(tbuff, *buffer, size); /*Flawfinder: ignore*/
  405. memcpy(tbuff + size, listbuf, listsize); /*Flawfinder: ignore*/
  406. size += listsize;
  407. delete [] *buffer;
  408. delete [] listbuf;
  409. *buffer = tbuff;
  410. }
  411. data = data->mListp;
  412. }
  413. }
  414. return size;
  415. }
  416. // increase reference count
  417. // increase reference count by 1
  418. void lsa_increase_ref_count(U8 *buffer, S32 offset)
  419. {
  420. if (get_register(buffer, LREG_FR))
  421. return;
  422. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  423. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  424. offset += get_register(buffer, LREG_HR) - 1;
  425. if ( (offset < get_register(buffer, LREG_HR))
  426. ||(offset >= get_register(buffer, LREG_HP)))
  427. {
  428. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  429. return;
  430. }
  431. S32 orig_offset = offset;
  432. LLScriptAllocEntry entry;
  433. bytestream2alloc_entry(entry, buffer, offset);
  434. entry.mReferenceCount++;
  435. alloc_entry2bytestream(buffer, orig_offset, entry);
  436. }
  437. // decrease reference count
  438. // decrease reference count by 1
  439. // if reference count == 0
  440. // set type to empty
  441. void lsa_decrease_ref_count(U8 *buffer, S32 offset)
  442. {
  443. if (get_register(buffer, LREG_FR))
  444. return;
  445. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  446. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  447. offset += get_register(buffer, LREG_HR) - 1;
  448. if ( (offset < get_register(buffer, LREG_HR))
  449. ||(offset >= get_register(buffer, LREG_HP)))
  450. {
  451. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  452. return;
  453. }
  454. S32 orig_offset = offset;
  455. LLScriptAllocEntry entry;
  456. bytestream2alloc_entry(entry, buffer, offset);
  457. entry.mReferenceCount--;
  458. if (entry.mReferenceCount < 0)
  459. {
  460. entry.mReferenceCount = 0;
  461. set_fault(buffer, LSRF_HEAP_ERROR);
  462. }
  463. else if (!entry.mReferenceCount)
  464. {
  465. if (entry.mType == LST_LIST)
  466. {
  467. S32 i, num = bytestream2integer(buffer, offset);
  468. for (i = 0; i < num; i++)
  469. {
  470. S32 list_offset = bytestream2integer(buffer, offset);
  471. lsa_decrease_ref_count(buffer, list_offset);
  472. }
  473. }
  474. entry.mType = LST_NULL;
  475. }
  476. alloc_entry2bytestream(buffer, orig_offset, entry);
  477. }
  478. char gLSAStringRead[TOP_OF_MEMORY]; /*Flawfinder: ignore*/
  479. LLScriptLibData *lsa_get_data(U8 *buffer, S32 &offset, BOOL b_dec_ref)
  480. {
  481. if (get_register(buffer, LREG_FR))
  482. return (new LLScriptLibData);
  483. S32 orig_offset = offset;
  484. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  485. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  486. offset += get_register(buffer, LREG_HR) - 1;
  487. if ( (offset < get_register(buffer, LREG_HR))
  488. ||(offset >= get_register(buffer, LREG_HP)))
  489. {
  490. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  491. return (new LLScriptLibData);
  492. }
  493. LLScriptAllocEntry entry;
  494. bytestream2alloc_entry(entry, buffer, offset);
  495. LLScriptLibData *retval = new LLScriptLibData;
  496. if (!entry.mType)
  497. {
  498. set_fault(buffer, LSRF_HEAP_ERROR);
  499. return retval;
  500. }
  501. retval->mType = (LSCRIPTType)entry.mType;
  502. if (entry.mType != LST_LIST)
  503. {
  504. switch(entry.mType)
  505. {
  506. case LST_INTEGER:
  507. retval->mInteger = bytestream2integer(buffer, offset);
  508. break;
  509. case LST_FLOATINGPOINT:
  510. retval->mFP = bytestream2float(buffer, offset);
  511. break;
  512. case LST_KEY:
  513. bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead)); // global sring buffer? for real? :(
  514. retval->mKey = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/
  515. strcpy(retval->mKey, gLSAStringRead); /*Flawfinder: ignore*/
  516. break;
  517. case LST_STRING:
  518. bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead));
  519. retval->mString = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/
  520. strcpy(retval->mString, gLSAStringRead); /*Flawfinder: ignore*/
  521. break;
  522. case LST_VECTOR:
  523. bytestream2vector(retval->mVec, buffer, offset);
  524. break;
  525. case LST_QUATERNION:
  526. bytestream2quaternion(retval->mQuat, buffer, offset);
  527. break;
  528. default:
  529. break;
  530. }
  531. }
  532. else
  533. {
  534. // get length of list
  535. S32 i, length = bytestream2integer(buffer, offset);
  536. LLScriptLibData *tip = retval;
  537. for (i = 0; i < length; i++)
  538. {
  539. S32 address = bytestream2integer(buffer, offset);
  540. tip->mListp = lsa_get_data(buffer, address, FALSE);
  541. tip = tip->mListp;
  542. }
  543. }
  544. if (retval->checkForMultipleLists())
  545. {
  546. set_fault(buffer, LSRF_NESTING_LISTS);
  547. }
  548. if (b_dec_ref)
  549. {
  550. lsa_decrease_ref_count(buffer, orig_offset);
  551. }
  552. return retval;
  553. }
  554. LLScriptLibData *lsa_get_list_ptr(U8 *buffer, S32 &offset, BOOL b_dec_ref)
  555. {
  556. if (get_register(buffer, LREG_FR))
  557. return (new LLScriptLibData);
  558. S32 orig_offset = offset;
  559. // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
  560. // and function clean up of ref counts isn't based on scope (a mistake, I know)
  561. offset += get_register(buffer, LREG_HR) - 1;
  562. if ( (offset < get_register(buffer, LREG_HR))
  563. ||(offset >= get_register(buffer, LREG_HP)))
  564. {
  565. set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
  566. return (new LLScriptLibData);
  567. }
  568. LLScriptAllocEntry entry;
  569. bytestream2alloc_entry(entry, buffer, offset);
  570. if (!entry.mType)
  571. {
  572. set_fault(buffer, LSRF_HEAP_ERROR);
  573. return NULL;
  574. }
  575. LLScriptLibData base, *tip = &base;
  576. if (entry.mType != LST_LIST)
  577. {
  578. return NULL;
  579. }
  580. else
  581. {
  582. // get length of list
  583. S32 i, length = bytestream2integer(buffer, offset);
  584. for (i = 0; i < length; i++)
  585. {
  586. S32 address = bytestream2integer(buffer, offset);
  587. tip->mListp = lsa_get_data(buffer, address, FALSE);
  588. tip = tip->mListp;
  589. }
  590. }
  591. if (b_dec_ref)
  592. {
  593. lsa_decrease_ref_count(buffer, orig_offset);
  594. }
  595. tip = base.mListp;
  596. base.mListp = NULL;
  597. return tip;
  598. }
  599. S32 lsa_cat_strings(U8 *buffer, S32 offset1, S32 offset2, S32 heapsize)
  600. {
  601. if (get_register(buffer, LREG_FR))
  602. return 0;
  603. LLScriptLibData *string1;
  604. LLScriptLibData *string2;
  605. if (offset1 != offset2)
  606. {
  607. string1 = lsa_get_data(buffer, offset1, TRUE);
  608. string2 = lsa_get_data(buffer, offset2, TRUE);
  609. }
  610. else
  611. {
  612. string1 = lsa_get_data(buffer, offset1, TRUE);
  613. string2 = lsa_get_data(buffer, offset2, TRUE);
  614. }
  615. if ( (!string1)
  616. ||(!string2))
  617. {
  618. set_fault(buffer, LSRF_HEAP_ERROR);
  619. delete string1;
  620. delete string2;
  621. return 0;
  622. }
  623. char *test1 = NULL, *test2 = NULL;
  624. if (string1->mType == LST_STRING)
  625. {
  626. test1 = string1->mString;
  627. }
  628. else if (string1->mType == LST_KEY)
  629. {
  630. test1 = string1->mKey;
  631. }
  632. if (string2->mType == LST_STRING)
  633. {
  634. test2 = string2->mString;
  635. }
  636. else if (string2->mType == LST_KEY)
  637. {
  638. test2 = string2->mKey;
  639. }
  640. if ( (!test1)
  641. ||(!test2))
  642. {
  643. set_fault(buffer, LSRF_HEAP_ERROR);
  644. delete string1;
  645. delete string2;
  646. return 0;
  647. }
  648. S32 size = (S32)strlen(test1) + (S32)strlen(test2) + 1; /*Flawfinder: ignore*/
  649. LLScriptLibData *string3 = new LLScriptLibData;
  650. string3->mType = LST_STRING;
  651. string3->mString = new char[size];
  652. strcpy(string3->mString, test1); /*Flawfinder: ignore*/
  653. strcat(string3->mString, test2); /*Flawfinder: ignore*/
  654. delete string1;
  655. delete string2;
  656. return lsa_heap_add_data(buffer, string3, heapsize, TRUE);
  657. }
  658. S32 lsa_cmp_strings(U8 *buffer, S32 offset1, S32 offset2)
  659. {
  660. if (get_register(buffer, LREG_FR))
  661. return 0;
  662. LLScriptLibData *string1;
  663. LLScriptLibData *string2;
  664. string1 = lsa_get_data(buffer, offset1, TRUE);
  665. string2 = lsa_get_data(buffer, offset2, TRUE);
  666. if ( (!string1)
  667. ||(!string2))
  668. {
  669. set_fault(buffer, LSRF_HEAP_ERROR);
  670. delete string1;
  671. delete string2;
  672. return 0;
  673. }
  674. char *test1 = NULL, *test2 = NULL;
  675. if (string1->mType == LST_STRING)
  676. {
  677. test1 = string1->mString;
  678. }
  679. else if (string1->mType == LST_KEY)
  680. {
  681. test1 = string1->mKey;
  682. }
  683. if (string2->mType == LST_STRING)
  684. {
  685. test2 = string2->mString;
  686. }
  687. else if (string2->mType == LST_KEY)
  688. {
  689. test2 = string2->mKey;
  690. }
  691. if ( (!test1)
  692. ||(!test2))
  693. {
  694. set_fault(buffer, LSRF_HEAP_ERROR);
  695. delete string1;
  696. delete string2;
  697. return 0;
  698. }
  699. S32 retval = strcmp(test1, test2);
  700. delete string1;
  701. delete string2;
  702. return retval;
  703. }
  704. void lsa_print_heap(U8 *buffer)
  705. {
  706. S32 offset = get_register(buffer, LREG_HR);
  707. S32 readoffset;
  708. S32 ivalue;
  709. F32 fpvalue;
  710. LLVector3 vvalue;
  711. LLQuaternion qvalue;
  712. char string[4096]; /*Flawfinder: ignore*/
  713. LLScriptAllocEntry entry;
  714. bytestream2alloc_entry(entry, buffer, offset);
  715. printf("HP: [0x%X]\n", get_register(buffer, LREG_HP));
  716. printf("==========\n");
  717. while (offset + entry.mSize < MAX_HEAP_SIZE)
  718. {
  719. printf("[0x%X] ", offset);
  720. printf("%s ", LSCRIPTTypeNames[entry.mType]);
  721. printf("Ref Count: %d ", entry.mReferenceCount);
  722. printf("Size: %d = ", entry.mSize);
  723. readoffset = offset;
  724. switch(entry.mType)
  725. {
  726. case LST_INTEGER:
  727. ivalue = bytestream2integer(buffer, readoffset);
  728. printf("%d\n", ivalue);
  729. break;
  730. case LST_FLOATINGPOINT:
  731. fpvalue = bytestream2float(buffer, readoffset);
  732. printf("%f\n", fpvalue);
  733. break;
  734. case LST_STRING:
  735. bytestream2char(string, buffer, readoffset, sizeof(string));
  736. printf("%s\n", string);
  737. break;
  738. case LST_KEY:
  739. bytestream2char(string, buffer, readoffset, sizeof(string));
  740. printf("%s\n", string);
  741. break;
  742. case LST_VECTOR:
  743. bytestream2vector(vvalue, buffer, readoffset);
  744. printf("< %f, %f, %f >\n", vvalue.mV[VX], vvalue.mV[VY], vvalue.mV[VZ]);
  745. break;
  746. case LST_QUATERNION:
  747. bytestream2quaternion(qvalue, buffer, readoffset);
  748. printf("< %f, %f, %f, %f >\n", qvalue.mQ[VX], qvalue.mQ[VY], qvalue.mQ[VZ], qvalue.mQ[VS]);
  749. break;
  750. case LST_LIST:
  751. ivalue = bytestream2integer(buffer, readoffset);
  752. printf("%d\n", ivalue);
  753. break;
  754. default:
  755. printf("\n");
  756. break;
  757. }
  758. offset += entry.mSize;
  759. bytestream2alloc_entry(entry, buffer, offset);
  760. }
  761. printf("[0x%X] ", offset);
  762. printf("%s ", LSCRIPTTypeNames[entry.mType]);
  763. printf("Ref Count: %d ", entry.mReferenceCount);
  764. printf("Size: %d\n", entry.mSize);
  765. printf("==========\n");
  766. }
  767. void lsa_fprint_heap(U8 *buffer, LLFILE *fp)
  768. {
  769. S32 offset = get_register(buffer, LREG_HR);
  770. S32 readoffset;
  771. S32 ivalue;
  772. F32 fpvalue;
  773. LLVector3 vvalue;
  774. LLQuaternion qvalue;
  775. char string[4096]; /*Flawfinder: ignore*/
  776. LLScriptAllocEntry entry;
  777. bytestream2alloc_entry(entry, buffer, offset);
  778. while (offset + entry.mSize < MAX_HEAP_SIZE)
  779. {
  780. fprintf(fp, "[0x%X] ", offset);
  781. fprintf(fp, "%s ", LSCRIPTTypeNames[entry.mType]);
  782. fprintf(fp, "Ref Count: %d ", entry.mReferenceCount);
  783. fprintf(fp, "Size: %d = ", entry.mSize);
  784. readoffset = offset;
  785. switch(entry.mType)
  786. {
  787. case LST_INTEGER:
  788. ivalue = bytestream2integer(buffer, readoffset);
  789. fprintf(fp, "%d\n", ivalue);
  790. break;
  791. case LST_FLOATINGPOINT:
  792. fpvalue = bytestream2float(buffer, readoffset);
  793. fprintf(fp, "%f\n", fpvalue);
  794. break;
  795. case LST_STRING:
  796. bytestream2char(string, buffer, readoffset, sizeof(string));
  797. fprintf(fp, "%s\n", string);
  798. break;
  799. case LST_KEY:
  800. bytestream2char(string, buffer, readoffset, sizeof(string));
  801. fprintf(fp, "%s\n", string);
  802. break;
  803. case LST_VECTOR:
  804. bytestream2vector(vvalue, buffer, readoffset);
  805. fprintf(fp, "< %f, %f, %f >\n", vvalue.mV[VX], vvalue.mV[VY], vvalue.mV[VZ]);
  806. break;
  807. case LST_QUATERNION:
  808. bytestream2quaternion(qvalue, buffer, readoffset);
  809. fprintf(fp, "< %f, %f, %f, %f >\n", qvalue.mQ[VX], qvalue.mQ[VY], qvalue.mQ[VZ], qvalue.mQ[VS]);
  810. break;
  811. case LST_LIST:
  812. ivalue = bytestream2integer(buffer, readoffset);
  813. fprintf(fp, "%d\n", ivalue);
  814. break;
  815. default:
  816. fprintf(fp, "\n");
  817. break;
  818. }
  819. offset += entry.mSize;
  820. bytestream2alloc_entry(entry, buffer, offset);
  821. }
  822. fprintf(fp, "[0x%X] ", offset);
  823. fprintf(fp, "%s ", LSCRIPTTypeNames[entry.mType]);
  824. fprintf(fp, "Ref Count: %d ", entry.mReferenceCount);
  825. fprintf(fp, "Size: %d", entry.mSize);
  826. fprintf(fp, "\n");
  827. }
  828. S32 lsa_cat_lists(U8 *buffer, S32 offset1, S32 offset2, S32 heapsize)
  829. {
  830. if (get_register(buffer, LREG_FR))
  831. return 0;
  832. LLScriptLibData *list1;
  833. LLScriptLibData *list2;
  834. if (offset1 != offset2)
  835. {
  836. list1 = lsa_get_data(buffer, offset1, TRUE);
  837. list2 = lsa_get_data(buffer, offset2, TRUE);
  838. }
  839. else
  840. {
  841. list1 = lsa_get_data(buffer, offset1, TRUE);
  842. list2 = lsa_get_data(buffer, offset2, TRUE);
  843. }
  844. if ( (!list1)
  845. ||(!list2))
  846. {
  847. set_fault(buffer, LSRF_HEAP_ERROR);
  848. delete list1;
  849. delete list2;
  850. return 0;
  851. }
  852. if ( (list1->mType != LST_LIST)
  853. ||(list2->mType != LST_LIST))
  854. {
  855. set_fault(buffer, LSRF_HEAP_ERROR);
  856. delete list1;
  857. delete list2;
  858. return 0;
  859. }
  860. LLScriptLibData *runner = list1;
  861. while (runner->mListp)
  862. {
  863. runner = runner->mListp;
  864. }
  865. runner->mListp = list2->mListp;
  866. list2->mListp = NULL;
  867. delete list2;
  868. return lsa_heap_add_data(buffer, list1, heapsize, TRUE);
  869. }
  870. S32 lsa_cmp_lists(U8 *buffer, S32 offset1, S32 offset2)
  871. {
  872. if (get_register(buffer, LREG_FR))
  873. return 0;
  874. LLScriptLibData *list1;
  875. LLScriptLibData *list2;
  876. if (offset1 != offset2)
  877. {
  878. list1 = lsa_get_data(buffer, offset1, TRUE);
  879. list2 = lsa_get_data(buffer, offset2, TRUE);
  880. }
  881. else
  882. {
  883. list1 = lsa_get_data(buffer, offset1, FALSE);
  884. list2 = lsa_get_data(buffer, offset2, TRUE);
  885. }
  886. if ( (!list1)
  887. ||(!list2))
  888. {
  889. set_fault(buffer, LSRF_HEAP_ERROR);
  890. delete list1;
  891. delete list2;
  892. return 0;
  893. }
  894. if ( (list1->mType != LST_LIST)
  895. ||(list2->mType != LST_LIST))
  896. {
  897. set_fault(buffer, LSRF_HEAP_ERROR);
  898. delete list1;
  899. delete list2;
  900. return 0;
  901. }
  902. S32 length1 = list1->getListLength();
  903. S32 length2 = list2->getListLength();
  904. delete list1;
  905. delete list2;
  906. return length1 - length2;
  907. }
  908. S32 lsa_preadd_lists(U8 *buffer, LLScriptLibData *data, S32 offset2, S32 heapsize)
  909. {
  910. if (get_register(buffer, LREG_FR))
  911. return 0;
  912. LLScriptLibData *list2 = lsa_get_data(buffer, offset2, TRUE);
  913. if (!list2)
  914. {
  915. set_fault(buffer, LSRF_HEAP_ERROR);
  916. delete list2;
  917. return 0;
  918. }
  919. if (list2->mType != LST_LIST)
  920. {
  921. set_fault(buffer, LSRF_HEAP_ERROR);
  922. delete list2;
  923. return 0;
  924. }
  925. LLScriptLibData *runner = data->mListp;
  926. while (runner->mListp)
  927. {
  928. runner = runner->mListp;
  929. }
  930. runner->mListp = list2->mListp;
  931. list2->mListp = data->mListp;
  932. return lsa_heap_add_data(buffer, list2, heapsize, TRUE);
  933. }
  934. S32 lsa_postadd_lists(U8 *buffer, S32 offset1, LLScriptLibData *data, S32 heapsize)
  935. {
  936. if (get_register(buffer, LREG_FR))
  937. return 0;
  938. LLScriptLibData *list1 = lsa_get_data(buffer, offset1, TRUE);
  939. if (!list1)
  940. {
  941. set_fault(buffer, LSRF_HEAP_ERROR);
  942. delete list1;
  943. return 0;
  944. }
  945. if (list1->mType != LST_LIST)
  946. {
  947. set_fault(buffer, LSRF_HEAP_ERROR);
  948. delete list1;
  949. return 0;
  950. }
  951. LLScriptLibData *runner = list1;
  952. while (runner->mListp)
  953. {
  954. runner = runner->mListp;
  955. }
  956. runner->mListp = data->mListp;
  957. return lsa_heap_add_data(buffer, list1, heapsize, TRUE);
  958. }
  959. LLScriptLibData* lsa_randomize(LLScriptLibData* src, S32 stride)
  960. {
  961. S32 number = src->getListLength();
  962. if (number <= 0)
  963. {
  964. return NULL;
  965. }
  966. if (stride <= 0)
  967. {
  968. stride = 1;
  969. }
  970. if(number % stride)
  971. {
  972. LLScriptLibData* retval = src->mListp;
  973. src->mListp = NULL;
  974. return retval;
  975. }
  976. S32 buckets = number / stride;
  977. // Copy everything into a special vector for sorting;
  978. std::vector<LLScriptLibData*> sort_array;
  979. sort_array.reserve(number);
  980. LLScriptLibData* temp = src->mListp;
  981. while(temp)
  982. {
  983. sort_array.push_back(temp);
  984. temp = temp->mListp;
  985. }
  986. // We cannot simply call random_shuffle or similar algorithm since
  987. // we need to obey the stride. So, we iterate over what we have
  988. // and swap each with a random other segment.
  989. S32 index = 0;
  990. S32 ii = 0;
  991. for(; ii < number; ii += stride)
  992. {
  993. index = ll_rand(buckets) * stride;
  994. for(S32 jj = 0; jj < stride; ++jj)
  995. {
  996. std::swap(sort_array[ii + jj], sort_array[index + jj]);
  997. }
  998. }
  999. // copy the pointers back out
  1000. ii = 1;
  1001. temp = sort_array[0];
  1002. while (ii < number)
  1003. {
  1004. temp->mListp = sort_array[ii++];
  1005. temp = temp->mListp;
  1006. }
  1007. temp->mListp = NULL;
  1008. src->mListp = NULL;
  1009. LLScriptLibData* ret_value = sort_array[0];
  1010. return ret_value;
  1011. }