diff options
author | Brian Robbins <brianrob@microsoft.com> | 2017-05-06 12:36:08 -0700 |
---|---|---|
committer | Vance Morrison <vancem@microsoft.com> | 2017-05-06 12:36:08 -0700 |
commit | 72ac46450bec8ea88ed023d9c1faf5a04556c834 (patch) | |
tree | 59085824f4268257d041ed9870f038216cd8ed45 /src/scripts | |
parent | 3ababc21ab334a2e37c6ba4115c946ea26a6f2fb (diff) | |
download | coreclr-72ac46450bec8ea88ed023d9c1faf5a04556c834.tar.gz coreclr-72ac46450bec8ea88ed023d9c1faf5a04556c834.tar.bz2 coreclr-72ac46450bec8ea88ed023d9c1faf5a04556c834.zip |
Log Events to EventPipe on Linux (#11433)
* Implement the EventPipe object model for providers and events.
* Plumb Runtime Events into EventPipe (#11145)
Plumb runtime ETW events into the EventPipe.
* Fix bug where all events except for SampleProfiler events were never enabled.
* Plumb EventPipeEventInstance through the EventPipe.
* Implement EventPipeFile and FastSerializer.
* Write event contents to the EventPipeFile.
* Only build EventPipe on Linux.
* Conditionally add a sentinel value marking event end.
* Send SampleProfiler events to the EventPipeFile.
* Fix provider ID printing to JSON file.
* Write the start date/time, timestamp, and clock frequency into the trace file.
* Support unloading of EventPipeProviders.
* Handle failure cases when we can't walk the stack or are shutting down.
* Fix a bug where we pass a null src pointer to memcpy.
Diffstat (limited to 'src/scripts')
-rw-r--r-- | src/scripts/genEventPipe.py | 500 | ||||
-rw-r--r-- | src/scripts/genXplatEventing.py | 89 | ||||
-rw-r--r-- | src/scripts/genXplatLttng.py | 6 |
3 files changed, 582 insertions, 13 deletions
diff --git a/src/scripts/genEventPipe.py b/src/scripts/genEventPipe.py new file mode 100644 index 0000000000..3a818ce1e0 --- /dev/null +++ b/src/scripts/genEventPipe.py @@ -0,0 +1,500 @@ +from __future__ import print_function +from genXplatEventing import * +from genXplatLttng import * +import os +import xml.dom.minidom as DOM + +stdprolog = """// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************** + +DO NOT MODIFY. AUTOGENERATED FILE. +This file is generated using the logic from <root>/src/scripts/genEventPipe.py + +******************************************************************/ +""" + +stdprolog_cmake = """# +# +#****************************************************************** + +#DO NOT MODIFY. AUTOGENERATED FILE. +#This file is generated using the logic from <root>/src/scripts/genEventPipe.py + +#****************************************************************** +""" + + +def generateClrEventPipeWriteEventsImpl( + providerName, eventNodes, allTemplates, exclusionListFile): + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + WriteEventImpl = [] + + # EventPipeEvent declaration + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + WriteEventImpl.append( + "EventPipeEvent *EventPipeEvent" + + eventName + + " = nullptr;\n") + + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + + # generate EventPipeEventEnabled function + eventEnabledImpl = """bool EventPipeEventEnabled%s() +{ + return EventPipeEvent%s->IsEnabled(); +} + +""" % (eventName, eventName) + WriteEventImpl.append(eventEnabledImpl) + + # generate EventPipeWriteEvent function + fnptype = [] + linefnptype = [] + fnptype.append("extern \"C\" ULONG EventPipeWriteEvent") + fnptype.append(eventName) + fnptype.append("(\n") + + if templateName: + template = allTemplates[templateName] + else: + template = None + + if template: + fnSig = template.signature + for paramName in fnSig.paramlist: + fnparam = fnSig.getParam(paramName) + wintypeName = fnparam.winType + typewName = palDataTypeMapping[wintypeName] + winCount = fnparam.count + countw = palDataTypeMapping[winCount] + + if paramName in template.structs: + linefnptype.append( + "%sint %s_ElementSize,\n" % + (lindent, paramName)) + + linefnptype.append(lindent) + linefnptype.append(typewName) + if countw != " ": + linefnptype.append(countw) + + linefnptype.append(" ") + linefnptype.append(fnparam.name) + linefnptype.append(",\n") + + if len(linefnptype) > 0: + del linefnptype[-1] + + fnptype.extend(linefnptype) + fnptype.append(")\n{\n") + checking = """ if (!EventPipeEventEnabled%s()) + return ERROR_SUCCESS; +""" % (eventName) + + fnptype.append(checking) + + WriteEventImpl.extend(fnptype) + + if template: + body = generateWriteEventBody(template, providerName, eventName) + WriteEventImpl.append(body) + else: + WriteEventImpl.append( + " EventPipe::WriteEvent(*EventPipeEvent" + + eventName + + ", nullptr, 0);\n") + + WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n") + + # EventPipeProvider and EventPipeEvent initialization + WriteEventImpl.append( + "extern \"C\" void Init" + + providerPrettyName + + "()\n{\n") + WriteEventImpl.append( + " EventPipeProvider" + + providerPrettyName + + " = new EventPipeProvider(" + + providerPrettyName + + "GUID);\n") + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + eventKeywords = eventNode.getAttribute('keywords') + eventKeywordsMask = generateEventKeywords(eventKeywords) + eventValue = eventNode.getAttribute('value') + eventVersion = eventNode.getAttribute('version') + eventLevel = eventNode.getAttribute('level') + eventLevel = eventLevel.replace("win:", "EventPipeEventLevel::") + exclusionInfo = parseExclusionList(exclusionListFile) + taskName = eventNode.getAttribute('task') + noStack = getStackWalkBit( + providerName, + taskName, + eventName, + exclusionInfo.nostack) + + initEvent = """ EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s,%d); +""" % (eventName, providerPrettyName, eventKeywordsMask, eventValue, eventVersion, eventLevel, int(noStack)) + + WriteEventImpl.append(initEvent) + WriteEventImpl.append("}") + + return ''.join(WriteEventImpl) + + +def generateWriteEventBody(template, providerName, eventName): + header = """ + char stackBuffer[%s]; + char *buffer = stackBuffer; + unsigned int offset = 0; + unsigned int size = %s; + bool fixedBuffer = true; + + bool success = true; +""" % (template.estimated_size, template.estimated_size) + + fnSig = template.signature + pack_list = [] + for paramName in fnSig.paramlist: + parameter = fnSig.getParam(paramName) + + if paramName in template.structs: + size = "(int)%s_ElementSize * (int)%s" % ( + paramName, parameter.prop) + if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]: + size = "(int)(%s)" % specialCaseSizes[template.name][paramName] + pack_list.append( + " success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" % + (paramName, size)) + elif paramName in template.arrays: + size = "sizeof(%s) * (int)%s" % ( + lttngDataTypeMapping[parameter.winType], + parameter.prop) + if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]: + size = "(int)(%s)" % specialCaseSizes[template.name][paramName] + pack_list.append( + " success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" % + (paramName, size)) + elif parameter.winType == "win:GUID": + pack_list.append( + " success &= WriteToBuffer(*%s, buffer, offset, size, fixedBuffer);" % + (parameter.name,)) + else: + pack_list.append( + " success &= WriteToBuffer(%s, buffer, offset, size, fixedBuffer);" % + (parameter.name,)) + + code = "\n".join(pack_list) + "\n\n" + + checking = """ if (!success) + { + if (!fixedBuffer) + delete[] buffer; + return ERROR_WRITE_FAULT; + }\n\n""" + + body = " EventPipe::WriteEvent(*EventPipeEvent" + \ + eventName + ", (BYTE *)buffer, size);\n" + + footer = """ + if (!fixedBuffer) + delete[] buffer; +""" + + return header + code + checking + body + footer + +providerGUIDMap = {} +providerGUIDMap[ + "{e13c0d23-ccbc-4e12-931b-d9cc2eee27e4}"] = "{0xe13c0d23,0xccbc,0x4e12,{0x93,0x1b,0xd9,0xcc,0x2e,0xee,0x27,0xe4}}" +providerGUIDMap[ + "{A669021C-C450-4609-A035-5AF59AF4DF18}"] = "{0xA669021C,0xC450,0x4609,{0xA0,0x35,0x5A,0xF5,0x9A,0xF4,0xDF,0x18}}" +providerGUIDMap[ + "{CC2BCBBA-16B6-4cf3-8990-D74C2E8AF500}"] = "{0xCC2BCBBA,0x16B6,0x4cf3,{0x89,0x90,0xD7,0x4C,0x2E,0x8A,0xF5,0x00}}" +providerGUIDMap[ + "{763FD754-7086-4dfe-95EB-C01A46FAF4CA}"] = "{0x763FD754,0x7086,0x4dfe,{0x95,0xEB,0xC0,0x1A,0x46,0xFA,0xF4,0xCA}}" + + +def generateGUID(tmpGUID): + return providerGUIDMap[tmpGUID] + +keywordMap = {} + + +def generateEventKeywords(eventKeywords): + mask = 0 + # split keywords if there are multiple + allKeywords = eventKeywords.split() + + for singleKeyword in allKeywords: + mask = mask | keywordMap[singleKeyword] + + return mask + + +def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory): + tree = DOM.parse(etwmanifest) + + with open(eventpipe_directory + "CMakeLists.txt", 'w') as topCmake: + topCmake.write(stdprolog_cmake + "\n") + topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2) + + project(eventpipe) + + set(CMAKE_INCLUDE_CURRENT_DIR ON) + include_directories(${CLR_DIR}/src/vm) + + add_library(eventpipe + STATIC\n""") + + for providerNode in tree.getElementsByTagName('provider'): + providerName = providerNode.getAttribute('name') + providerName = providerName.replace("Windows-", '') + providerName = providerName.replace("Microsoft-", '') + + providerName_File = providerName.replace('-', '') + providerName_File = providerName_File.lower() + + topCmake.write(' "%s.cpp"\n' % (providerName_File)) + topCmake.write(' "eventpipehelpers.cpp"\n') + topCmake.write(""" ) + + # Install the static eventpipe library + install(TARGETS eventpipe DESTINATION lib) + """) + + topCmake.close() + + +def generateEventPipeHelperFile(etwmanifest, eventpipe_directory): + with open(eventpipe_directory + "eventpipehelpers.cpp", 'w') as helper: + helper.write(stdprolog) + helper.write(""" +#include "stdlib.h" + +bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer) +{ + newSize *= 1.5; + _ASSERTE(newSize > size); // check for overflow + + if (newSize < 32) + newSize = 32; + + char *newBuffer = new char[newSize]; + + memcpy(newBuffer, buffer, currLen); + + if (!fixedBuffer) + delete[] buffer; + + buffer = newBuffer; + size = newSize; + fixedBuffer = false; + + return true; +} + +bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +{ + if(!src) return true; + if (offset + len > size) + { + if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, src, len); + offset += len; + return true; +} + +bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +{ + if(!str) return true; + unsigned int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str); + + if (offset + byteCount > size) + { + if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, str, byteCount); + offset += byteCount; + return true; +} + +bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +{ + if(!str) return true; + unsigned int len = strlen(str) + 1; + if (offset + len > size) + { + if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, str, len); + offset += len; + return true; +} + +""") + + tree = DOM.parse(etwmanifest) + + for providerNode in tree.getElementsByTagName('provider'): + providerName = providerNode.getAttribute('name') + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + helper.write( + "extern \"C\" void Init" + + providerPrettyName + + "();\n\n") + + helper.write("extern \"C\" void InitProvidersAndEvents()\n{\n") + for providerNode in tree.getElementsByTagName('provider'): + providerName = providerNode.getAttribute('name') + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + helper.write(" Init" + providerPrettyName + "();\n") + helper.write("}") + + helper.close() + + +def generateEventPipeImplFiles( + etwmanifest, eventpipe_directory, exclusionListFile): + tree = DOM.parse(etwmanifest) + coreclrRoot = os.getcwd() + for providerNode in tree.getElementsByTagName('provider'): + providerGUID = providerNode.getAttribute('guid') + providerGUID = generateGUID(providerGUID) + providerName = providerNode.getAttribute('name') + + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerName_File = providerPrettyName.replace('-', '') + providerName_File = providerName_File.lower() + providerPrettyName = providerPrettyName.replace('-', '_') + eventpipefile = eventpipe_directory + providerName_File + ".cpp" + eventpipeImpl = open(eventpipefile, 'w') + eventpipeImpl.write(stdprolog) + + header = """ +#include \"%s/src/vm/common.h\" +#include \"%s/src/vm/eventpipeprovider.h\" +#include \"%s/src/vm/eventpipeevent.h\" +#include \"%s/src/vm/eventpipe.h\" + +bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer); +bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); +bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); +bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); + +template <typename T> +bool WriteToBuffer(const T &value, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +{ + if (sizeof(T) + offset > size) + { + if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) + return false; + } + + *(T *)(buffer + offset) = value; + offset += sizeof(T); + return true; +} + +""" % (coreclrRoot, coreclrRoot, coreclrRoot, coreclrRoot) + + eventpipeImpl.write(header) + eventpipeImpl.write( + "GUID const " + + providerPrettyName + + "GUID = " + + providerGUID + + ";\n") + eventpipeImpl.write( + "EventPipeProvider *EventPipeProvider" + + providerPrettyName + + " = nullptr;\n") + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') + eventpipeImpl.write( + generateClrEventPipeWriteEventsImpl( + providerName, + eventNodes, + allTemplates, + exclusionListFile) + "\n") + eventpipeImpl.close() + + +def generateEventPipeFiles( + etwmanifest, eventpipe_directory, exclusionListFile): + eventpipe_directory = eventpipe_directory + "/" + tree = DOM.parse(etwmanifest) + + if not os.path.exists(eventpipe_directory): + os.makedirs(eventpipe_directory) + + # generate Cmake file + generateEventPipeCmakeFile(etwmanifest, eventpipe_directory) + + # generate helper file + generateEventPipeHelperFile(etwmanifest, eventpipe_directory) + + # generate all keywords + for keywordNode in tree.getElementsByTagName('keyword'): + keywordName = keywordNode.getAttribute('name') + keywordMask = keywordNode.getAttribute('mask') + keywordMap[keywordName] = int(keywordMask, 0) + + # generate .cpp file for each provider + generateEventPipeImplFiles( + etwmanifest, + eventpipe_directory, + exclusionListFile) + +import argparse +import sys + + +def main(argv): + + # parse the command line + parser = argparse.ArgumentParser( + description="Generates the Code required to instrument eventpipe logging mechanism") + + required = parser.add_argument_group('required arguments') + required.add_argument('--man', type=str, required=True, + help='full path to manifest containig the description of events') + required.add_argument('--intermediate', type=str, required=True, + help='full path to eventprovider intermediate directory') + required.add_argument('--exc', type=str, required=True, + help='full path to exclusion list') + args, unknown = parser.parse_known_args(argv) + if unknown: + print('Unknown argument(s): ', ', '.join(unknown)) + return const.UnknownArguments + + sClrEtwAllMan = args.man + intermediate = args.intermediate + exclusionListFile = args.exc + + generateEventPipeFiles(sClrEtwAllMan, intermediate, exclusionListFile) + +if __name__ == '__main__': + return_code = main(sys.argv[1:]) + sys.exit(return_code) diff --git a/src/scripts/genXplatEventing.py b/src/scripts/genXplatEventing.py index 6c6498d3de..6968d293e9 100644 --- a/src/scripts/genXplatEventing.py +++ b/src/scripts/genXplatEventing.py @@ -39,7 +39,7 @@ stdprolog_cmake=""" #****************************************************************** """ -lindent = " "; +lindent = " "; palDataTypeMapping ={ #constructed types "win:null" :" ", @@ -282,18 +282,17 @@ def generateClrallEvents(eventNodes,allTemplates): #generate EventEnabled clrallEvents.append("inline BOOL EventEnabled") clrallEvents.append(eventName) - clrallEvents.append("() {return XplatEventLogger::IsEventLoggingEnabled() && EventXplatEnabled") - clrallEvents.append(eventName+"();}\n\n") + clrallEvents.append("() {return ") + clrallEvents.append("EventPipeEventEnabled" + eventName + "() || ") + clrallEvents.append("(XplatEventLogger::IsEventLoggingEnabled() && EventXplatEnabled") + clrallEvents.append(eventName+"());}\n\n") #generate FireEtw functions fnptype = [] fnbody = [] fnptype.append("inline ULONG FireEtw") fnptype.append(eventName) fnptype.append("(\n") - fnbody.append(lindent) - fnbody.append("if (!EventEnabled") - fnbody.append(eventName) - fnbody.append("()) {return ERROR_SUCCESS;}\n") + line = [] fnptypeline = [] @@ -339,11 +338,22 @@ def generateClrallEvents(eventNodes,allTemplates): fnptype.extend(fnptypeline) fnptype.append("\n)\n{\n") fnbody.append(lindent) - fnbody.append("return FireEtXplat") + fnbody.append("ULONG status = EventPipeWriteEvent" + eventName + "(" + ''.join(line) + ");\n") + fnbody.append(lindent) + fnbody.append("if(XplatEventLogger::IsEventLoggingEnabled())\n") + fnbody.append(lindent) + fnbody.append("{\n") + fnbody.append(lindent) + fnbody.append(lindent) + fnbody.append("status &= FireEtXplat") fnbody.append(eventName) fnbody.append("(") fnbody.extend(line) fnbody.append(");\n") + fnbody.append(lindent) + fnbody.append("}\n") + fnbody.append(lindent) + fnbody.append("return status;\n") fnbody.append("}\n\n") clrallEvents.extend(fnptype) @@ -400,6 +410,57 @@ def generateClrXplatEvents(eventNodes, allTemplates): return ''.join(clrallEvents) +def generateClrEventPipeWriteEvents(eventNodes, allTemplates): + clrallEvents = [] + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + + #generate EventPipeEventEnabled and EventPipeWriteEvent functions + eventenabled = [] + writeevent = [] + fnptypeline = [] + + eventenabled.append("extern \"C\" bool EventPipeEventEnabled") + eventenabled.append(eventName) + eventenabled.append("();\n") + + writeevent.append("extern \"C\" ULONG EventPipeWriteEvent") + writeevent.append(eventName) + writeevent.append("(\n") + + if templateName: + template = allTemplates[templateName] + fnSig = template.signature + + for params in fnSig.paramlist: + fnparam = fnSig.getParam(params) + wintypeName = fnparam.winType + typewName = palDataTypeMapping[wintypeName] + winCount = fnparam.count + countw = palDataTypeMapping[winCount] + + if params in template.structs: + fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params)) + + fnptypeline.append(lindent) + fnptypeline.append(typewName) + fnptypeline.append(countw) + fnptypeline.append(" ") + fnptypeline.append(fnparam.name) + fnptypeline.append(",\n") + + #remove trailing commas + if len(fnptypeline) > 0: + del fnptypeline[-1] + + writeevent.extend(fnptypeline) + writeevent.append("\n);\n") + clrallEvents.extend(eventenabled) + clrallEvents.extend(writeevent) + + return ''.join(clrallEvents) + #generates the dummy header file which is used by the VM as entry point to the logging Functions def generateclrEtwDummy(eventNodes,allTemplates): clretmEvents = [] @@ -670,15 +731,19 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile): clrallevents = incDir + "/clretwallmain.h" clrxplatevents = incDir + "/clrxplatevents.h" + clreventpipewriteevents = incDir + "/clreventpipewriteevents.h" Clrallevents = open(clrallevents,'w') Clrxplatevents = open(clrxplatevents,'w') + Clreventpipewriteevents = open(clreventpipewriteevents,'w') Clrallevents.write(stdprolog + "\n") Clrxplatevents.write(stdprolog + "\n") + Clreventpipewriteevents.write(stdprolog + "\n") - Clrallevents.write("\n#include \"clrxplatevents.h\"\n\n") - + Clrallevents.write("\n#include \"clrxplatevents.h\"\n") + Clrallevents.write("#include \"clreventpipewriteevents.h\"\n\n") + for providerNode in tree.getElementsByTagName('provider'): templateNodes = providerNode.getElementsByTagName('template') allTemplates = parseTemplateNodes(templateNodes) @@ -689,8 +754,12 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile): #pal: create clrallevents.h Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates) + "\n") + #eventpipe: create clreventpipewriteevents.h + Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates) + "\n") + Clrxplatevents.close() Clrallevents.close() + Clreventpipewriteevents.close() class EventExclusions: def __init__(self): diff --git a/src/scripts/genXplatLttng.py b/src/scripts/genXplatLttng.py index 6dd60b0a0b..fae0e120da 100644 --- a/src/scripts/genXplatLttng.py +++ b/src/scripts/genXplatLttng.py @@ -594,7 +594,7 @@ bool ResizeBuffer(char *&buffer, int& size, int currLen, int newSize, bool &fixe bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& size, bool &fixedBuffer) { if (!src) return true; - if (offset + len) + if (offset + len > size) { if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) return false; @@ -610,7 +610,7 @@ bool WriteToBuffer(PCWSTR str, char *&buffer, int& offset, int& size, bool &fixe if (!str) return true; int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str); - if (offset + byteCount) + if (offset + byteCount > size) { if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer)) return false; @@ -625,7 +625,7 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool { if (!str) return true; int len = strlen(str) + 1; - if (offset + len) + if (offset + len > size) { if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) return false; |