On 4/11/24 18:07, Tom Tromey wrote: >>>>>> "Tom" == Tom de Vries writes: > > Tom> PR python/31631 reports a gdb internal error when doing: > Tom> ... > Tom> (gdb) python gdb.selected_inferior().read_memory (0, 0xffffffffffffffff) > Tom> utils.c:709: internal-error: virtual memory exhausted. > Tom> A problem internal to GDB has been detected, > Tom> further debugging may prove unreliable. > Tom> ... > > Tom> Fix this by throwing a python MemoryError, such that we have instead: > Tom> ... > Tom> (gdb) python gdb.selected_inferior().read_memory (0, 0xffffffffffffffff) > Tom> Python Exception : > Tom> Error occurred in Python. > Tom> (gdb) > Tom> ... > > I tend to think you will regret opening this door, because I imagine > there are a large number of ways to crash gdb by passing nonsensical > values to Python APIs. > Hm, ok then let's hope I don't regret it. > Tom> @request("readMemory") > Tom> @capability("supportsReadMemoryRequest") > Tom> def read_memory(*, memoryReference: str, offset: int = 0, count: int, **extra): > Tom> addr = int(memoryReference, 0) + offset > Tom> - buf = gdb.selected_inferior().read_memory(addr, count) > Tom> + oom = False > Tom> + try: > Tom> + buf = gdb.selected_inferior().read_memory(addr, count) > Tom> + except MemoryError: > Tom> + oom = True > Tom> + if oom: > Tom> + raise DAPException("Out of memory") > > This should probably chain the memory error in the except block and > re-throw. See https://peps.python.org/pep-3134/ > Ack, that's what I had initially, but I ran into an error that I can no longer reproduce ... so, I'm not sure what happened there. Anyway, fixed. > However I don't really understand why this is needed. Isn't the > exception already propagated back to the server thread? > Without it I run into: ... FAIL: gdb.dap/memory.exp: exceptions in log file ... because in the dap log we have: ... READ: <<<{"seq": 7, "type": "request", "command": "readMemory", "arguments": {"memoryReference": "0x402010", "count": 18446744073709551615}}>>> Traceback (most recent call last): File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/server.py", line 157, in _handle_command body = _commands[params["command"]](**args) File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/server.py", line 300, in check return func(*args, **kwargs) File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/server.py", line 360, in sync_call return send_gdb_with_response(lambda: func(**args)) File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/server.py", line 514, in send_gdb_with_response raise val File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/server.py", line 470, in __call__ val = self.fn() File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/server.py", line 360, in return send_gdb_with_response(lambda: func(**args)) File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/startup.py", line 113, in ensure_gdb_thread return func(*args, **kwargs) File "/data/vries/gdb/leap-15-5/build/gdb/data-directory/python/gdb/dap/memory.py", line 28, in read_memory buf = gdb.selected_inferior().read_memory(addr, count) MemoryError WROTE: <<<{"request_seq": 7, "type": "response", "command": "readMemory", "success": false, "message": ""}>>> ... So that needs fixing here: ... diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index 7eb87177710..8408232eceb 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -173,6 +173,9 @@ class Server: log_stack(LogLevel.FULL) result["success"] = False result["message"] = str(e) + except MemoryError as e: + result["success"] = False + result["message"] = str(e) except BaseException as e: ... But I couldn't come up with a good rationale as to why I should handle MemoryError differently from BaseException, so I decided to catch it locally and turn it into a DAPException. > Tom> + /* We used to use xmalloc, which does this trick to avoid malloc > Tom> + returning a nullptr for a valid reason. Keep doing the same. */ > Tom> + if (length == 0) > Tom> + length = 1; > > This is most likely a workaround for vendor implementations of malloc > that return NULL for malloc(0). See > https://www.gnu.org/software/gnulib/manual/html_node/malloc.html > > However, here this is not necessary, because a 0-length memory read is > meaningless, and so this case can simply be reported as an error. I went for backward compatibility here, but ok, fixed. Updated version attached. Thanks, - Tom