{"record":{"id":"3ca2efe1a9f6618f","repo":"NationalSecurityAgency/ghidra","slug":"cannot-send-tracermi-message-with-excessive-length-3ca2ef","errorCode":null,"errorMessage":"Cannot send TraceRmi message with excessive length","messagePattern":"Cannot send TraceRmi message with excessive length","errorType":"exception","errorClass":"TraceRmiError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/util.py","lineNumber":34,"sourceCode":"from concurrent.futures import Future\nimport socket\nfrom typing import TypeVar\n\nfrom google.protobuf import message as _message\n\nM = TypeVar('M', bound=_message.Message)\nMAX_MSG_LENGTH = 1 << 16 # Plenty and shouldn't cause OOM\n\n\ndef send_length(s: socket.socket, value: int) -> None:\n    s.sendall(value.to_bytes(4, 'big'))\n\n\ndef send_delimited(s: socket.socket, msg: _message.Message) -> None:\n    data = msg.SerializeToString()\n    size = len(data)\n    if size > MAX_MSG_LENGTH:\n        raise TraceRmiError(\"Cannot send TraceRmi message with excessive length\")\n    send_length(s, size)\n    s.sendall(data)\n\n\ndef recv_all(s, size: int) -> bytes:\n    buf = b''\n    while len(buf) < size:\n        part = s.recv(size - len(buf))\n        if len(part) == 0:\n            return buf\n        buf += part\n    return buf\n    # return s.recv(size, socket.MSG_WAITALL)\n\n\ndef recv_length(s: socket.socket) -> int:\n    buf = recv_all(s, 4)\n    if len(buf) < 4:","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-rmi-trace/src/main/py/src/ghidratrace/util.py#L16-L52","documentation":"Intended to be raised as TraceRmiError by send_delimited() when a serialized protobuf message exceeds MAX_MSG_LENGTH (1<<16 = 64 KiB) before being placed on the socket. The guard exists to prevent oversized messages from being sent. IMPORTANT BUG: util.py raises 'TraceRmiError' but never imports or defines it, so if this line actually executes it throws NameError: name 'TraceRmiError' is not defined instead of the documented error.","triggerScenarios":"Serializing a Value carrying a very large bytes/string payload (e.g. put_bytes of a big memory region in a single message), a large object tree, or a method return with bulky data such that SerializeToString() exceeds 64 KiB.","commonSituations":"Bulk memory writes/reads done in one call rather than chunked; large symbol/module lists; transferring big blobs over TraceRMI.","solutions":["Chunk large payloads into multiple smaller messages below 64 KiB each.","For memory bytes, write/read in page-sized or smaller ranges instead of one giant buffer.","If developing, fix the latent bug by importing/defining TraceRmiError in util.py so the guard is usable."],"exampleFix":"# before\nclient.put_bytes(addr, huge_buffer)  # > 64KiB\n# after\nCHUNK = 32 * 1024\nfor off in range(0, len(huge_buffer), CHUNK):\n    client.put_bytes(addr.add(off), huge_buffer[off:off+CHUNK])","handlingStrategy":"validation","validationCode":"from ghidratrace.util import MAX_MSG_LENGTH\ndata = msg.SerializeToString()\nif len(data) > MAX_MSG_LENGTH:\n    raise ValueError(f'message {len(data)} > {MAX_MSG_LENGTH}; chunk it')","typeGuard":null,"tryCatchPattern":"try:\n    send_delimited(s, msg)\nexcept (ValueError, NameError):\n    # chunk payload below 64KiB and resend","preventionTips":["Chunk memory writes to <= 32KiB ranges.","Fix the latent TraceRmiError import bug in util.py if you maintain the codebase."],"tags":["network","trace-rmi","serialization","size-limit","latent-bug"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}