void TTDebuggerSourceLocation::SetLocation(const TTDebuggerSourceLocation& other) { #if !ENABLE_TTD_DEBUGGING AssertMsg(false, "Debugger is not enabled so you shouldn't be calling this"); this->Clear(); #else this->m_etime = other.m_etime; this->m_ftime = other.m_ftime; this->m_ltime = other.m_ltime; this->m_docid = other.m_docid; this->m_functionLine = other.m_functionLine; this->m_functionColumn = other.m_functionColumn; this->m_line = other.m_line; this->m_column = other.m_column; if(this->m_sourceFile != nullptr) { delete[] this->m_sourceFile; } this->m_sourceFile = nullptr; if(other.m_sourceFile != nullptr) { size_t char16Length = wcslen(other.m_sourceFile) + 1; size_t byteLength = char16Length * sizeof(char16); this->m_sourceFile = new char16[char16Length]; js_memcpy_s(this->m_sourceFile, byteLength, other.m_sourceFile, byteLength); } #endif }
Js::Var CreateBuffer(const uint8* buf, uint size, void* user_data) { Context* ctx = (Context*)user_data; ArrayBuffer* arrayBuffer = ctx->scriptContext->GetLibrary()->CreateArrayBuffer(size); js_memcpy_s(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength(), buf, size); return arrayBuffer; }
const StElemInfo *ReadOnlyDynamicProfileInfo::GetStElemInfo(FunctionBody *functionBody, ProfileId stElemId) { Assert(functionBody); Assert(stElemId < functionBody->GetProfiledStElemCount()); // This data is accessed multiple times. Since the original profile data may be changing on the foreground thread, // the first time it's accessed it will be copied from the original profile data (if we're jitting in the // background). if(!stElemInfo) { if(backgroundAllocator) { // Jitting in the background StElemInfo *const info = AnewArray(backgroundAllocator, StElemInfo, functionBody->GetProfiledStElemCount()); js_memcpy_s( info, functionBody->GetProfiledStElemCount() * sizeof(info[0]), profileInfo->GetStElemInfo(), functionBody->GetProfiledStElemCount() * sizeof(info[0])); stElemInfo = info; } else { // Jitting in the foreground stElemInfo = profileInfo->GetStElemInfo(); } } return &stElemInfo[stElemId]; }
bool BigInt::FResize(long clu) { AssertBiNoVal(this); ulong *prglu; if (clu <= m_cluMax) return true; clu += clu; if (m_prglu == m_rgluInit) { if ((INT_MAX / sizeof(ulong) < clu) || (NULL == (prglu = (ulong *)malloc(clu * sizeof(ulong))))) return false; if (0 < m_clu) js_memcpy_s(prglu, clu * sizeof(ulong), m_prglu, m_clu * sizeof(ulong)); } else if (NULL == (prglu = (ulong *)realloc(m_prglu, clu * sizeof(ulong)))) return false; m_prglu = prglu; m_cluMax = clu; AssertBiNoVal(this); return true; }
void TTDebuggerSourceLocation::SetLocation(int64 etime, int64 ftime, int64 ltime, Js::FunctionBody* body, ULONG line, LONG column) { #if !ENABLE_TTD_DEBUGGING AssertMsg(false, "Debugger is not enabled so you shouldn't be calling this"); this->Clear(); #else this->m_etime = etime; this->m_ftime = ftime; this->m_ltime = ltime; this->m_docid = body->GetUtf8SourceInfo()->GetSourceInfoId(); this->m_functionLine = body->GetLineNumber(); this->m_functionColumn = body->GetColumnNumber(); this->m_line = (uint32)line; this->m_column = (uint32)column; if(this->m_sourceFile != nullptr) { delete[] this->m_sourceFile; } this->m_sourceFile = nullptr; const char16* sourceFile = body->GetSourceContextInfo()->url; if(sourceFile != nullptr) { size_t char16Length = wcslen(sourceFile) + 1; size_t byteLength = char16Length * sizeof(char16); this->m_sourceFile = new char16[char16Length]; js_memcpy_s(this->m_sourceFile, byteLength, sourceFile, byteLength); } #endif }
Utf8SourceInfo* Utf8SourceInfo::New(ScriptContext* scriptContext, LPCUTF8 utf8String, int32 length, size_t numBytes, SRCINFO const* srcInfo) { utf8char_t * newUtf8String = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), utf8char_t, numBytes + 1); js_memcpy_s(newUtf8String, numBytes + 1, utf8String, numBytes + 1); return NewWithNoCopy(scriptContext, newUtf8String, length, numBytes, srcInfo); }
void TTDComparePath::WritePathToConsole(ThreadContext* threadContext, bool printNewline, char16* namebuff) const { if(this->m_prefix != nullptr) { this->m_prefix->WritePathToConsole(threadContext, false, namebuff); } if(this->m_stepKind == StepKind::PropertyData || this->m_stepKind == StepKind::PropertyGetter || this->m_stepKind == StepKind::PropertySetter) { const Js::PropertyRecord* pRecord = threadContext->GetPropertyName((Js::PropertyId)this->m_step.IndexOrPID); js_memcpy_s(namebuff, 256 * sizeof(char16), pRecord->GetBuffer(), pRecord->GetLength() * sizeof(char16)); namebuff[pRecord->GetLength()] = _u('\0'); } bool isFirst = (this->m_prefix == nullptr); switch(this->m_stepKind) { case StepKind::Empty: break; case StepKind::Root: wprintf(_u("root#%I64i"), this->m_step.IndexOrPID); break; case StepKind::PropertyData: wprintf(_u("%ls%ls"), (isFirst ? _u("") : _u(".")), namebuff); break; case StepKind::PropertyGetter: wprintf(_u("%ls<%ls"), (isFirst ? _u("") : _u(".")), namebuff); break; case StepKind::PropertySetter: wprintf(_u("%ls>%ls"), (isFirst ? _u("") : _u(".")), namebuff); break; case StepKind::Array: wprintf(_u("[%I64i]"), this->m_step.IndexOrPID); break; case StepKind::Scope: wprintf(_u("%ls_scope[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.IndexOrPID); break; case StepKind::SlotArray: wprintf(_u("%ls_slots[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.IndexOrPID); break; case StepKind::FunctionBody: wprintf(_u("%ls%ls"), (isFirst ? _u("") : _u(".")), this->m_step.OptName); break; case StepKind::Special: wprintf(_u("%ls_%ls"), (isFirst ? _u("") : _u(".")), this->m_step.OptName); break; case StepKind::SpecialArray: wprintf(_u("%ls_%ls[%I64i]"), (isFirst ? _u("") : _u(".")), this->m_step.OptName, this->m_step.IndexOrPID); break; default: TTDAssert(false, "Unknown tag in switch statement!!!"); break; } if(printNewline) { wprintf(_u("\n")); } }
// This will make a copy of the entire buffer InternalString *InternalString::New(ArenaAllocator* alloc, const char16* content, charcount_t length) { size_t bytelength = sizeof(char16) * length; DWORD* allocbuffer = (DWORD*)alloc->Alloc(sizeof(DWORD) + bytelength + sizeof(char16)); allocbuffer[0] = (DWORD) bytelength; char16* buffer = (char16*)(allocbuffer+1); js_memcpy_s(buffer, bytelength, content, bytelength); buffer[length] = L'\0'; InternalString* newInstance = Anew(alloc, InternalString, buffer, length); return newInstance; }
void BVFixed::Copy(const BVFixed*bv) { AssertBV(bv); Assert(len >= bv->len); #if 1 js_memcpy_s(&this->data[0], WordCount() * sizeof(BVUnit), &bv->data[0], bv->WordCount() * sizeof(BVUnit)); #else this->for_each(bv, &BVUnit::Copy); #endif }
TTDebuggerSourceLocation::TTDebuggerSourceLocation(const TTDebuggerSourceLocation& other) : m_etime(other.m_etime), m_ftime(other.m_ftime), m_ltime(other.m_ltime), m_sourceFile(nullptr), m_docid(other.m_docid), m_functionLine(other.m_functionLine), m_functionColumn(other.m_functionColumn), m_line(other.m_line), m_column(other.m_column) { if(other.m_sourceFile != nullptr) { size_t char16Length = wcslen(other.m_sourceFile) + 1; size_t byteLength = char16Length * sizeof(char16); this->m_sourceFile = new char16[char16Length]; js_memcpy_s(this->m_sourceFile, byteLength, other.m_sourceFile, byteLength); } }
bool BigInt::FInitFromRglu(ulong *prglu, long clu) { AssertBi(this); Assert(clu >= 0); Assert(prglu != 0); if (clu > m_cluMax && !FResize(clu)) return false; m_clu = clu; if (clu > 0) js_memcpy_s(m_prglu, m_clu * sizeof(ulong), prglu, clu * sizeof(ulong)); AssertBi(this); return true; }
// This will make a copy of the entire buffer // Allocated using recycler memory InternalString *InternalString::New(Recycler* recycler, const char16* content, charcount_t length) { size_t bytelength = sizeof(char16) * length; // Allocate 3 extra bytes, two for the first DWORD with the size, the third for the null character // This is so that we can pretend that internal strings are BSTRs for purposes of clients who want to use // it as thus const unsigned char offset = sizeof(DWORD)/sizeof(char16); InternalString* newInstance = RecyclerNewPlusLeaf(recycler, bytelength + (sizeof(DWORD) + sizeof(char16)), InternalString, nullptr, length, offset); DWORD* allocbuffer = (DWORD*) (newInstance + 1); allocbuffer[0] = (DWORD) bytelength; char16* buffer = (char16*)(allocbuffer + 1); js_memcpy_s(buffer, bytelength, content, bytelength); buffer[length] = L'\0'; newInstance->m_content = (const char16*) allocbuffer; return newInstance; }
Var JavascriptGeneratorFunction::EntryAsyncFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(stackArgs, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); RecyclableObject* prototype = scriptContext->GetLibrary()->GetNull(); // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap // and use that buffer for this InterpreterStackFrame. Var* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Var, stackArgs.Info.Count); js_memcpy_s(argsHeapCopy, sizeof(Var) * stackArgs.Info.Count, stackArgs.Values, sizeof(Var) * stackArgs.Info.Count); Arguments heapArgs(callInfo, argsHeapCopy); JavascriptExceptionObject* e = nullptr; JavascriptPromiseResolveOrRejectFunction* resolve; JavascriptPromiseResolveOrRejectFunction* reject; JavascriptPromiseAsyncSpawnExecutorFunction* executor = library->CreatePromiseAsyncSpawnExecutorFunction( JavascriptPromise::EntryJavascriptPromiseAsyncSpawnExecutorFunction, scriptContext->GetLibrary()->CreateGenerator(heapArgs, JavascriptAsyncFunction::FromVar(function)->GetGeneratorVirtualScriptFunction(), prototype), stackArgs[0]); JavascriptPromise* promise = library->CreatePromise(); JavascriptPromise::InitializePromise(promise, &resolve, &reject, scriptContext); try { CALL_FUNCTION(executor, CallInfo(CallFlags_Value, 3), library->GetUndefined(), resolve, reject); } catch (JavascriptExceptionObject* ex) { e = ex; } if (e != nullptr) { JavascriptPromise::TryRejectWithExceptionObject(e, reject, scriptContext); } return promise; }
void ExternalCallEventLogEntry_ProcessArgs(EventLogEntry* evt, int32 rootDepth, Js::JavascriptFunction* function, uint32 argc, Js::Var* argv, double beginTime, UnlinkableSlabAllocator& alloc) { ExternalCallEventLogEntry* callEvt = GetInlineEventDataAs<ExternalCallEventLogEntry, EventKind::ExternalCallTag>(evt); callEvt->AdditionalInfo = alloc.SlabAllocateStruct<ExternalCallEventLogEntry_AdditionalInfo>(); callEvt->RootNestingDepth = rootDepth; callEvt->ArgCount = argc + 1; static_assert(sizeof(TTDVar) == sizeof(Js::Var), "These need to be the same size (and have same bit layout) for this to work!"); callEvt->ArgArray = alloc.SlabAllocateArray<TTDVar>(callEvt->ArgCount); callEvt->ArgArray[0] = static_cast<TTDVar>(function); js_memcpy_s(callEvt->ArgArray + 1, (callEvt->ArgCount - 1) * sizeof(TTDVar), argv, argc * sizeof(Js::Var)); //Initialize this info in case we terminate without completing (e.g. exit(1)) callEvt->AdditionalInfo->BeginTime = beginTime; callEvt->AdditionalInfo->EndTime = -1.0; callEvt->ReturnValue = nullptr; callEvt->AdditionalInfo->LastNestedEventTime = TTD_EVENT_MAXTIME; }
void BVFixed::CopyBits(const BVFixed * bv, BVIndex i) { AssertBV(bv); BVIndex offset = BVUnit::Offset(i); BVIndex position = BVUnit::Position(i); BVIndex len = bv->WordCount() - position; BVIndex copylen = min(WordCount(), len); if (offset == 0) { js_memcpy_s(&this->data[0], copylen * sizeof(BVUnit), &bv->data[BVUnit::Position(i)], copylen * sizeof(BVUnit)); } else { BVIndex pos = position; for (BVIndex j = 0; j < copylen; j++) { Assert(pos < bv->WordCount()); this->data[j] = bv->data[pos]; this->data[j].ShiftRight(offset); pos++; if (pos >= bv->WordCount()) { break; } BVUnit temp = bv->data[pos]; temp.ShiftLeft(BVUnit::BitsPerWord - offset); this->data[j].Or(temp); } } #if DBG for (BVIndex curr = i; curr < i + this->Length(); curr++) { Assert(this->Test(curr - i) == bv->Test(curr)); } #endif }
Var JavascriptGeneratorFunction::EntryGeneratorFunctionImplementation(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(stackArgs, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptGeneratorFunction* generatorFunction = JavascriptGeneratorFunction::FromVar(function); // InterpreterStackFrame takes a pointer to the args, so copy them to the recycler heap // and use that buffer for this InterpreterStackFrame. Var* argsHeapCopy = RecyclerNewArray(scriptContext->GetRecycler(), Var, stackArgs.Info.Count); js_memcpy_s(argsHeapCopy, sizeof(Var) * stackArgs.Info.Count, stackArgs.Values, sizeof(Var) * stackArgs.Info.Count); Arguments heapArgs(callInfo, argsHeapCopy); DynamicObject* prototype = scriptContext->GetLibrary()->CreateGeneratorConstructorPrototypeObject(); JavascriptGenerator* generator = scriptContext->GetLibrary()->CreateGenerator(heapArgs, generatorFunction->scriptFunction, prototype); // Set the prototype from constructor JavascriptOperators::OrdinaryCreateFromConstructor(function, generator, prototype, scriptContext); Assert(!(callInfo.Flags & CallFlags_New)); return generator; }
LeakReport::UrlRecord * LeakReport::LogUrl(char16 const * url, void * globalObject) { UrlRecord * record = NoCheckHeapNewStruct(UrlRecord); size_t length = wcslen(url) + 1; // Add 1 for the NULL. char16* urlCopy = NoCheckHeapNewArray(char16, length); js_memcpy_s(urlCopy, (length - 1) * sizeof(char16), url, (length - 1) * sizeof(char16)); urlCopy[length - 1] = _u('\0'); record->url = urlCopy; #if _MSC_VER record->time = _time64(NULL); #else record->time = time(NULL); #endif record->tid = ::GetCurrentThreadId(); record->next = nullptr; record->scriptEngine = nullptr; record->globalObject = globalObject; AutoCriticalSection autocs(&s_cs); if (LeakReport::urlRecordHead == nullptr) { Assert(LeakReport::urlRecordTail == nullptr); LeakReport::urlRecordHead = record; LeakReport::urlRecordTail = record; } else { LeakReport::urlRecordTail->next = record; LeakReport::urlRecordTail = record; } return record; }
void InterpreterThunkEmitter::NewThunkBlock() { Assert(this->thunkCount == 0); BYTE* buffer; BYTE* currentBuffer; DWORD bufferSize = BlockSize; DWORD thunkCount = 0; allocation = emitBufferManager.AllocateBuffer(bufferSize, &buffer, /*readWrite*/ true); currentBuffer = buffer; #ifdef _M_X64 PrologEncoder prologEncoder(allocator); prologEncoder.EncodeSmallProlog(PrologSize, StackAllocSize); DWORD pdataSize = prologEncoder.SizeOfPData(); #elif defined(_M_ARM32_OR_ARM64) DWORD pdataSize = sizeof(RUNTIME_FUNCTION); #else DWORD pdataSize = 0; #endif DWORD bytesRemaining = bufferSize; DWORD bytesWritten = 0; DWORD epilogSize = sizeof(Epilog); // Ensure there is space for PDATA at the end BYTE* pdataStart = currentBuffer + (bufferSize - Math::Align(pdataSize, EMIT_BUFFER_ALIGNMENT)); BYTE* epilogStart = pdataStart - Math::Align(epilogSize, EMIT_BUFFER_ALIGNMENT); // Copy the thunk buffer and modify it. js_memcpy_s(currentBuffer, bytesRemaining, InterpreterThunk, HeaderSize); EncodeInterpreterThunk(currentBuffer, buffer, HeaderSize, epilogStart, epilogSize); currentBuffer += HeaderSize; bytesRemaining -= HeaderSize; // Copy call buffer DWORD callSize = sizeof(Call); while(currentBuffer < epilogStart - callSize) { js_memcpy_s(currentBuffer, bytesRemaining, Call, callSize); #if _M_ARM int offset = (epilogStart - (currentBuffer + JmpOffset)); Assert(offset >= 0); DWORD encodedOffset = EncoderMD::BranchOffset_T2_24(offset); DWORD encodedBranch = /*opcode=*/ 0x9000F000 | encodedOffset; Emit(currentBuffer, JmpOffset, encodedBranch); #elif _M_ARM64 int64 offset = (epilogStart - (currentBuffer + JmpOffset)); Assert(offset >= 0); DWORD encodedOffset = EncoderMD::BranchOffset_26(offset); DWORD encodedBranch = /*opcode=*/ 0x14000000 | encodedOffset; Emit(currentBuffer, JmpOffset, encodedBranch); #else // jump requires an offset from the end of the jump instruction. int offset = (int)(epilogStart - (currentBuffer + JmpOffset + sizeof(int))); Assert(offset >= 0); Emit(currentBuffer, JmpOffset, offset); #endif currentBuffer += callSize; bytesRemaining -= callSize; thunkCount++; } // Fill any gap till start of epilog bytesWritten = FillDebugBreak(currentBuffer, (DWORD)(epilogStart - currentBuffer)); bytesRemaining -= bytesWritten; currentBuffer += bytesWritten; // Copy epilog bytesWritten = CopyWithAlignment(currentBuffer, bytesRemaining, Epilog, epilogSize, EMIT_BUFFER_ALIGNMENT); currentBuffer += bytesWritten; bytesRemaining -= bytesWritten; // Generate and register PDATA #if PDATA_ENABLED BYTE* epilogEnd = epilogStart + epilogSize; DWORD functionSize = (DWORD)(epilogEnd - buffer); Assert(pdataStart == currentBuffer); #ifdef _M_X64 Assert(bytesRemaining >= pdataSize); BYTE* pdata = prologEncoder.Finalize(buffer, functionSize, pdataStart); bytesWritten = CopyWithAlignment(pdataStart, bytesRemaining, pdata, pdataSize, EMIT_BUFFER_ALIGNMENT); #elif defined(_M_ARM32_OR_ARM64) RUNTIME_FUNCTION pdata; GeneratePdata(buffer, functionSize, &pdata); bytesWritten = CopyWithAlignment(pdataStart, bytesRemaining, (const BYTE*)&pdata, pdataSize, EMIT_BUFFER_ALIGNMENT); #endif void* pdataTable; PDataManager::RegisterPdata((PRUNTIME_FUNCTION) pdataStart, (ULONG_PTR) buffer, (ULONG_PTR) epilogEnd, &pdataTable); #endif if (!emitBufferManager.CommitReadWriteBufferForInterpreter(allocation, buffer, bufferSize)) { Js::Throw::OutOfMemory(); } // Call to set VALID flag for CFG check ThreadContext::GetContextForCurrentThread()->SetValidCallTargetForCFG(buffer); // Update object state only at the end when everything has succeeded - and no exceptions can be thrown. ThunkBlock* block = this->thunkBlocks.PrependNode(allocator, buffer); UNREFERENCED_PARAMETER(block); #if PDATA_ENABLED block->SetPdata(pdataTable); #endif this->thunkCount = thunkCount; this->thunkBuffer = buffer; }
// SharedArrayBuffer.prototype.slice Var SharedArrayBuffer::EntrySlice(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'"); Assert(!(callInfo.Flags & CallFlags_New)); if (!SharedArrayBuffer::Is(args[0])) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject); } JavascriptLibrary* library = scriptContext->GetLibrary(); SharedArrayBuffer* currentBuffer = SharedArrayBuffer::FromVar(args[0]); int64 currentLen = (int64)currentBuffer->GetByteLength(); int64 start = 0, end = 0; int64 newLen = 0; // If no start or end arguments, use the entire length if (args.Info.Count < 2) { newLen = currentLen; } else { start = JavascriptArray::GetIndexFromVar(args[1], currentLen, scriptContext); // If no end argument, use length as the end if (args.Info.Count < 3 || args[2] == library->GetUndefined()) { end = currentLen; } else { end = JavascriptArray::GetIndexFromVar(args[2], currentLen, scriptContext); } newLen = end > start ? end - start : 0; } // We can't have allocated an SharedArrayBuffer with byteLength > MaxArrayBufferLength. // start and end are clamped to valid indices, so the new length also cannot exceed MaxArrayBufferLength. // Therefore, should be safe to cast down newLen to uint32. Assert(newLen < MaxSharedArrayBufferLength); uint32 newbyteLength = static_cast<uint32>(newLen); SharedArrayBuffer* newBuffer = nullptr; if (scriptContext->GetConfig()->IsES6SpeciesEnabled()) { Var constructorVar = JavascriptOperators::SpeciesConstructor(currentBuffer, scriptContext->GetLibrary()->GetSharedArrayBufferConstructor(), scriptContext); JavascriptFunction* constructor = JavascriptFunction::FromVar(constructorVar); Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(newbyteLength, scriptContext) }; Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs)); Js::Var newVar = JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext); if (!SharedArrayBuffer::Is(newVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject); } newBuffer = SharedArrayBuffer::FromVar(newVar); if (newBuffer == currentBuffer) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedSharedArrayBufferObject); } if (newBuffer->GetByteLength() < newbyteLength) { JavascriptError::ThrowTypeError(scriptContext, JSERR_ArgumentOutOfRange, _u("SharedArrayBuffer.prototype.slice")); } } else { newBuffer = library->CreateSharedArrayBuffer(newbyteLength); } Assert(newBuffer); Assert(newBuffer->GetByteLength() >= newbyteLength); // Don't bother doing memcpy if we aren't copying any elements if (newbyteLength > 0) { AssertMsg(currentBuffer->GetBuffer() != nullptr, "buffer must not be null when we copy from it"); js_memcpy_s(newBuffer->GetBuffer(), newbyteLength, currentBuffer->GetBuffer() + start, newbyteLength); } return newBuffer; }