public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: Simon Marchi <simark@simark.ca>, 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: Wed, 17 Apr 2024 10:29:08 +0200	[thread overview]
Message-ID: <5dda7d2f-82c9-4154-86fa-8bedeb962f0e@suse.de> (raw)
In-Reply-To: <40c3c863-1369-4f4f-bef4-f2d35357c8eb@simark.ca>

On 4/16/24 21:10, Simon Marchi wrote:
> 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
> 

Hi Simon,

thanks for the report.

I've submitted a fix here ( 
https://sourceware.org/pipermail/gdb-patches/2024-April/208178.html ).

Thanks,
- Tom


      reply	other threads:[~2024-04-17  8:28 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
2024-04-17  8:29       ` Tom de Vries [this message]

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=5dda7d2f-82c9-4154-86fa-8bedeb962f0e@suse.de \
    --to=tdevries@suse.de \
    --cc=gdb-patches@sourceware.org \
    --cc=simark@simark.ca \
    --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).