public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Simon Marchi <simark@simark.ca>
To: Tom de Vries <tdevries@suse.de>, Tom Tromey <tom@tromey.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH] [gdb/python] Throw MemoryError in inferior.read_memory if malloc fails
Date: Tue, 16 Apr 2024 15:10:02 -0400	[thread overview]
Message-ID: <40c3c863-1369-4f4f-bef4-f2d35357c8eb@simark.ca> (raw)
In-Reply-To: <b2a4f986-37f7-4838-b535-fb2d3ee90ef7@suse.de>

On 4/12/24 3:09 AM, Tom de Vries wrote:
> On 4/11/24 18:07, Tom Tromey wrote:
>>>>>>> "Tom" == Tom de Vries <tdevries@suse.de> 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 <class 'MemoryError'>:
>> 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 <lambda>
>     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

In an Asan-enabled build, I get:


 74 (gdb) python gdb.selected_inferior().read_memory (0, 0xffffffffffffffff)^M
 75 =================================================================^M
 76 ^[[1m^[[31m==791047==ERROR: AddressSanitizer: requested allocation size 0xffffffffffffffff (0x800 after adjustments for alignment, red zones etc.) exceeds maximum supported size of 0x100    00000000 (thread T0)^M
 77 ^[[1m^[[0m    #0 0x7f02c58d49cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69^M
 78     #1 0x55cc5937f257 in infpy_read_memory /home/smarchi/src/binutils-gdb/gdb/python/py-inferior.c:565^M
 79     #2 0x7f02c4ea9709 in method_vectorcall_VARARGS_KEYWORDS ../Objects/descrobject.c:364^M
 80 ^M
 81 ==791047==HINT: if you don't care about these errors you may set allocator_may_return_null=1^M
 82 SUMMARY: AddressSanitizer: allocation-size-too-big ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69 in __interceptor_malloc^M

Simon

  parent reply	other threads:[~2024-04-16 19:10 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-11 10:52 Tom de Vries
2024-04-11 16:07 ` Tom Tromey
2024-04-12  7:09   ` Tom de Vries
2024-04-15 16:16     ` Tom Tromey
2024-04-16 13:55       ` Tom de Vries
2024-04-16 19:10     ` Simon Marchi [this message]
2024-04-17  8:29       ` Tom de Vries

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=40c3c863-1369-4f4f-bef4-f2d35357c8eb@simark.ca \
    --to=simark@simark.ca \
    --cc=gdb-patches@sourceware.org \
    --cc=tdevries@suse.de \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).