S32 lsa_postadd_lists(U8 *buffer, S32 offset1, LLScriptLibData *data, S32 heapsize) { if (get_register(buffer, LREG_FR)) return 0; LLScriptLibData *list1 = lsa_get_data(buffer, offset1, TRUE); if (!list1) { set_fault(buffer, LSRF_HEAP_ERROR); delete list1; return 0; } if (list1->mType != LST_LIST) { set_fault(buffer, LSRF_HEAP_ERROR); delete list1; return 0; } LLScriptLibData *runner = list1; while (runner->mListp) { runner = runner->mListp; } runner->mListp = data->mListp; return lsa_heap_add_data(buffer, list1, heapsize, TRUE); }
S32 lsa_cmp_strings(U8 *buffer, S32 offset1, S32 offset2) { if (get_register(buffer, LREG_FR)) return 0; LLScriptLibData *string1; LLScriptLibData *string2; string1 = lsa_get_data(buffer, offset1, TRUE); string2 = lsa_get_data(buffer, offset2, TRUE); if ( (!string1) ||(!string2)) { set_fault(buffer, LSRF_HEAP_ERROR); delete string1; delete string2; return 0; } char *test1 = NULL, *test2 = NULL; if (string1->mType == LST_STRING) { test1 = string1->mString; } else if (string1->mType == LST_KEY) { test1 = string1->mKey; } if (string2->mType == LST_STRING) { test2 = string2->mString; } else if (string2->mType == LST_KEY) { test2 = string2->mKey; } if ( (!test1) ||(!test2)) { set_fault(buffer, LSRF_HEAP_ERROR); delete string1; delete string2; return 0; } S32 retval = strcmp(test1, test2); delete string1; delete string2; return retval; }
S32 lsa_cat_lists(U8 *buffer, S32 offset1, S32 offset2, S32 heapsize) { if (get_register(buffer, LREG_FR)) return 0; LLScriptLibData *list1; LLScriptLibData *list2; if (offset1 != offset2) { list1 = lsa_get_data(buffer, offset1, TRUE); list2 = lsa_get_data(buffer, offset2, TRUE); } else { list1 = lsa_get_data(buffer, offset1, TRUE); list2 = lsa_get_data(buffer, offset2, TRUE); } if ( (!list1) ||(!list2)) { set_fault(buffer, LSRF_HEAP_ERROR); delete list1; delete list2; return 0; } if ( (list1->mType != LST_LIST) ||(list2->mType != LST_LIST)) { set_fault(buffer, LSRF_HEAP_ERROR); delete list1; delete list2; return 0; } LLScriptLibData *runner = list1; while (runner->mListp) { runner = runner->mListp; } runner->mListp = list2->mListp; list2->mListp = NULL; delete list2; return lsa_heap_add_data(buffer, list1, heapsize, TRUE); }
LLScriptLibData *lsa_get_list_ptr(U8 *buffer, S32 &offset, BOOL b_dec_ref) { if (get_register(buffer, LREG_FR)) return (new LLScriptLibData); S32 orig_offset = offset; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return (new LLScriptLibData); } LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); if (!entry.mType) { set_fault(buffer, LSRF_HEAP_ERROR); return NULL; } LLScriptLibData base, *tip = &base; if (entry.mType != LST_LIST) { return NULL; } else { // get length of list S32 i, length = bytestream2integer(buffer, offset); for (i = 0; i < length; i++) { S32 address = bytestream2integer(buffer, offset); tip->mListp = lsa_get_data(buffer, address, FALSE); tip = tip->mListp; } } if (b_dec_ref) { lsa_decrease_ref_count(buffer, orig_offset); } tip = base.mListp; base.mListp = NULL; return tip; }
void LLScriptHeapRunTime::increaseRefCount(S32 address) { if (!mBuffer) return; if (!address) { // unused temp string entry return; } // get current reference count S32 toffset = address + 4; S32 count = bytestream2integer(mBuffer, toffset); count++; if (mbPrint) printf("0x%X inc ref count %d\n", address - mHeapRegister, count); // see which type it is U8 type = *(mBuffer + toffset); if (type == LSCRIPTTypeByte[LST_STRING]) { toffset = address + 4; integer2bytestream(mBuffer, toffset, count); } // TO DO: put list stuff here! else { set_fault(mBuffer, LSRF_HEAP_ERROR); } }
S32 LLScriptHeapRunTime::addData(char *string) { if (!mBuffer) return 0; S32 size = strlen(string) + 1; S32 block_offset = findOpenBlock(size + HEAP_BLOCK_HEADER_SIZE); if (mCurrentPosition) { S32 offset = mCurrentPosition; if (offset + block_offset + HEAP_BLOCK_HEADER_SIZE + LSCRIPTDataSize[LST_INTEGER] >= mStackPointer) { set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION); return 0; } // cool, we've found a spot! // set offset integer2bytestream(mBuffer, offset, block_offset); // set reference count integer2bytestream(mBuffer, offset, 1); // set type *(mBuffer + offset++) = LSCRIPTTypeByte[LST_STRING]; // plug in data char2bytestream(mBuffer, offset, string); if (mbPrint) printf("0x%X created ref count %d\n", mCurrentPosition - mHeapRegister, 1); // now, zero out next offset to prevent "trouble" // offset = mCurrentPosition + size + HEAP_BLOCK_HEADER_SIZE; // integer2bytestream(mBuffer, offset, 0); } return mCurrentPosition; }
S32 lsa_cmp_lists(U8 *buffer, S32 offset1, S32 offset2) { if (get_register(buffer, LREG_FR)) return 0; LLScriptLibData *list1; LLScriptLibData *list2; if (offset1 != offset2) { list1 = lsa_get_data(buffer, offset1, TRUE); list2 = lsa_get_data(buffer, offset2, TRUE); } else { list1 = lsa_get_data(buffer, offset1, FALSE); list2 = lsa_get_data(buffer, offset2, TRUE); } if ( (!list1) ||(!list2)) { set_fault(buffer, LSRF_HEAP_ERROR); delete list1; delete list2; return 0; } if ( (list1->mType != LST_LIST) ||(list2->mType != LST_LIST)) { set_fault(buffer, LSRF_HEAP_ERROR); delete list1; delete list2; return 0; } S32 length1 = list1->getListLength(); S32 length2 = list2->getListLength(); delete list1; delete list2; return length1 - length2; }
void lsa_decrease_ref_count(U8 *buffer, S32 offset) { if (get_register(buffer, LREG_FR)) return; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return; } S32 orig_offset = offset; LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); entry.mReferenceCount--; if (entry.mReferenceCount < 0) { entry.mReferenceCount = 0; set_fault(buffer, LSRF_HEAP_ERROR); } else if (!entry.mReferenceCount) { if (entry.mType == LST_LIST) { S32 i, num = bytestream2integer(buffer, offset); for (i = 0; i < num; i++) { S32 list_offset = bytestream2integer(buffer, offset); lsa_decrease_ref_count(buffer, list_offset); } } entry.mType = LST_NULL; } alloc_entry2bytestream(buffer, orig_offset, entry); }
void LLScriptHeapRunTime::decreaseRefCount(S32 address) { if (!mBuffer) return; if (!address) { // unused temp string entry return; } // get offset S32 toffset = address; // read past offset (rely on function side effect) bytestream2integer(mBuffer, toffset); // get current reference count S32 count = bytestream2integer(mBuffer, toffset); // see which type it is U8 type = *(mBuffer + toffset); if (type == LSCRIPTTypeByte[LST_STRING]) { count--; if (mbPrint) printf("0x%X dec ref count %d\n", address - mHeapRegister, count); toffset = address + 4; integer2bytestream(mBuffer, toffset, count); if (!count) { // we can blow this one away removeData(address); } } // TO DO: put list stuff here! else { set_fault(mBuffer, LSRF_HEAP_ERROR); } }
void lsa_increase_ref_count(U8 *buffer, S32 offset) { if (get_register(buffer, LREG_FR)) return; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return; } S32 orig_offset = offset; LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); entry.mReferenceCount++; alloc_entry2bytestream(buffer, orig_offset, entry); }
S32 lsa_cat_strings(U8 *buffer, S32 offset1, S32 offset2, S32 heapsize) { if (get_register(buffer, LREG_FR)) return 0; LLScriptLibData *string1; LLScriptLibData *string2; if (offset1 != offset2) { string1 = lsa_get_data(buffer, offset1, TRUE); string2 = lsa_get_data(buffer, offset2, TRUE); } else { string1 = lsa_get_data(buffer, offset1, TRUE); string2 = lsa_get_data(buffer, offset2, TRUE); } if ( (!string1) ||(!string2)) { set_fault(buffer, LSRF_HEAP_ERROR); delete string1; delete string2; return 0; } char *test1 = NULL, *test2 = NULL; if (string1->mType == LST_STRING) { test1 = string1->mString; } else if (string1->mType == LST_KEY) { test1 = string1->mKey; } if (string2->mType == LST_STRING) { test2 = string2->mString; } else if (string2->mType == LST_KEY) { test2 = string2->mKey; } if ( (!test1) ||(!test2)) { set_fault(buffer, LSRF_HEAP_ERROR); delete string1; delete string2; return 0; } S32 size = (S32)strlen(test1) + (S32)strlen(test2) + 1; /*Flawfinder: ignore*/ LLScriptLibData *string3 = new LLScriptLibData; string3->mType = LST_STRING; string3->mString = new char[size]; strcpy(string3->mString, test1); /*Flawfinder: ignore*/ strcat(string3->mString, test2); /*Flawfinder: ignore*/ delete string1; delete string2; return lsa_heap_add_data(buffer, string3, heapsize, TRUE); }
LLScriptLibData *lsa_get_data(U8 *buffer, S32 &offset, BOOL b_dec_ref) { if (get_register(buffer, LREG_FR)) return (new LLScriptLibData); S32 orig_offset = offset; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return (new LLScriptLibData); } LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); LLScriptLibData *retval = new LLScriptLibData; if (!entry.mType) { set_fault(buffer, LSRF_HEAP_ERROR); return retval; } retval->mType = (LSCRIPTType)entry.mType; if (entry.mType != LST_LIST) { switch(entry.mType) { case LST_INTEGER: retval->mInteger = bytestream2integer(buffer, offset); break; case LST_FLOATINGPOINT: retval->mFP = bytestream2float(buffer, offset); break; case LST_KEY: bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead)); // global sring buffer? for real? :( retval->mKey = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/ strcpy(retval->mKey, gLSAStringRead); /*Flawfinder: ignore*/ break; case LST_STRING: bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead)); retval->mString = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/ strcpy(retval->mString, gLSAStringRead); /*Flawfinder: ignore*/ break; case LST_VECTOR: bytestream2vector(retval->mVec, buffer, offset); break; case LST_QUATERNION: bytestream2quaternion(retval->mQuat, buffer, offset); break; default: break; } } else { // get length of list S32 i, length = bytestream2integer(buffer, offset); LLScriptLibData *tip = retval; for (i = 0; i < length; i++) { S32 address = bytestream2integer(buffer, offset); tip->mListp = lsa_get_data(buffer, address, FALSE); tip = tip->mListp; } } if (retval->checkForMultipleLists()) { set_fault(buffer, LSRF_NESTING_LISTS); } if (b_dec_ref) { lsa_decrease_ref_count(buffer, orig_offset); } return retval; }
S32 lsa_heap_add_data(U8 *buffer, LLScriptLibData *data, S32 heapsize, BOOL b_delete) { if (get_register(buffer, LREG_FR)) return 1; LLScriptAllocEntry entry, nextentry; S32 hr = get_register(buffer, LREG_HR); S32 hp = get_register(buffer, LREG_HP); S32 current_offset, next_offset, offset = hr; S32 size = 0; switch(data->mType) { case LST_INTEGER: size = 4; break; case LST_FLOATINGPOINT: size = 4; break; case LST_KEY: // NOTE: babbage: defensive as some library calls set data to NULL size = data->mKey ? (S32)strlen(data->mKey) + 1 : 1; /*Flawfinder: ignore*/ break; case LST_STRING: // NOTE: babbage: defensive as some library calls set data to NULL size = data->mString ? (S32)strlen(data->mString) + 1 : 1; /*Flawfinder: ignore*/ break; case LST_LIST: // list data 4 bytes of number of entries followed by number of pointer size = 4 + 4*data->getListLength(); if (data->checkForMultipleLists()) { set_fault(buffer, LSRF_NESTING_LISTS); } break; case LST_VECTOR: size = 12; break; case LST_QUATERNION: size = 16; break; default: break; } current_offset = offset; bytestream2alloc_entry(entry, buffer, offset); do { hp = get_register(buffer, LREG_HP); if (!entry.mType) { if (entry.mSize >= size + SIZEOF_SCRIPT_ALLOC_ENTRY + 4) { offset = current_offset; lsa_split_block(buffer, offset, size, entry); entry.mType = data->mType; entry.mSize = size; entry.mReferenceCount = 1; offset = current_offset; alloc_entry2bytestream(buffer, offset, entry); lsa_insert_data(buffer, offset, data, entry, heapsize); hp = get_register(buffer, LREG_HP); S32 new_hp = current_offset + size + 2*SIZEOF_SCRIPT_ALLOC_ENTRY; if (new_hp >= hr + heapsize) { break; } if (new_hp > hp) { set_register(buffer, LREG_HP, new_hp); hp = get_register(buffer, LREG_HP); } if (b_delete) delete data; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) if (current_offset <= hp) return current_offset - hr + 1; else return hp - hr + 1; } else if (entry.mSize >= size) { entry.mType = data->mType; entry.mReferenceCount = 1; offset = current_offset; alloc_entry2bytestream(buffer, offset, entry); lsa_insert_data(buffer, offset, data, entry, heapsize); hp = get_register(buffer, LREG_HP); if (b_delete) delete data; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) return current_offset - hr + 1; } } offset += entry.mSize; if (offset < hr + heapsize) { next_offset = offset; bytestream2alloc_entry(nextentry, buffer, offset); if (!nextentry.mType && !entry.mType) { entry.mSize += nextentry.mSize + SIZEOF_SCRIPT_ALLOC_ENTRY; offset = current_offset; alloc_entry2bytestream(buffer, offset, entry); } else { current_offset = next_offset; entry = nextentry; } // this works whether we are bumping out or coming in S32 new_hp = current_offset + size + 2*SIZEOF_SCRIPT_ALLOC_ENTRY; // make sure we aren't about to be stupid if (new_hp >= hr + heapsize) { break; } if (new_hp > hp) { set_register(buffer, LREG_HP, new_hp); hp = get_register(buffer, LREG_HP); } } else { break; } } while (1); set_fault(buffer, LSRF_STACK_HEAP_COLLISION); reset_hp_to_safe_spot(buffer); if (b_delete) delete data; return 0; }
S32 LLScriptHeapRunTime::findOpenBlock(S32 size) { S32 offset; S32 toffset; U8 blocktype; while(1) { if (mCurrentPosition + size >= mStackPointer) { set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION); mCurrentPosition = 0; } toffset = mCurrentPosition; offset = bytestream2integer(mBuffer, toffset); if (!offset) { // we've reached the end of Heap, return this location if we'll fit // do we need to coalesce with last empty space? if (mLastEmpty) { // ok, that everything from mLastEmpty to us is empty, so we don't need a block // zero out the last empty's offset and return it mCurrentPosition = mLastEmpty; integer2bytestream(mBuffer, mLastEmpty, 0); mLastEmpty = 0; } // now, zero out next offset to prevent "trouble" offset = mCurrentPosition + size; integer2bytestream(mBuffer, offset, 0); // set HP to appropriate value set_register(mBuffer, LREG_HP, mCurrentPosition + size); return size; } // ok, is this slot empty? toffset += LSCRIPTDataSize[LST_INTEGER]; blocktype = *(mBuffer + toffset++); if (!blocktype) { // Empty block, do we need to coalesce? if (mLastEmpty) { coalesce(mLastEmpty, mCurrentPosition); mCurrentPosition = mLastEmpty; toffset = mCurrentPosition; offset = bytestream2integer(mBuffer, toffset); } // do we fit in this block? if (offset >= size) { // do we need to split the block? (only split if splitting will leave > HEAP_BLOCK_SPLIT_THRESHOLD bytes of free space) if (offset - HEAP_BLOCK_SPLIT_THRESHOLD >= size) { split(mCurrentPosition, size); return size; } else return offset; } } // nothing found, keep looking mCurrentPosition += offset; } // fake return to prevent warnings mCurrentPosition = 0; return 0; }