This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] Fix memory corruption when writting in inferior memory


Hello,

This occurs on AiX (4.3.2 or 5.1). The case that we came across was with
an Ada program that contains a function with a string as a parameter.
We noticed that the string was not always correctly passed when the
function was called from GDB. For instance, we saw:

   (gdb) call trace ("1234567890")
   Trace_Message:
   (gdb)

But we expected:

   (gdb) call trace ("1234567890")
   Trace_Message: 1234567890
   (gdb)

Contrary to C, our Ada-mode no longer uses malloc() to allocate some
memory for the string, but rather pushes the string on the stack.
As you may have noticed, the string length is not a multiple of 4.

A string in Ada is an array of characters. Arrays in Ada is actually
fat pointers, that is a structure containings 2 fields: the first field
is a pointer to the array, and the second field is a pointer to a
structure containing the 2 bounds.

In C parlance, a string would be defined like this:

   struct { int UB0; int LB0; } string___XUB;
   struct { char *P_ARRAY; struct string___XUB *P_BOUNDS; } string;
   
So, what happens when GDB the Ada mode pushes the string on the stack
is the following (say SP is equal to Addr, Addr being a multiple of 4).
The pushing is done by push_bytes(), which eventually calls
target_xfer_memory() which in our case is set to child_xfer_memory()
in rs6000-nat.c.

  1. GDB pushes the bounds (8 bytes) at Addr - 8
  2. GDB pushes the string (10 bytes), at Addr - 18
  3. GDB pushes the string struct (8 bytes) at Addr - 26.

child_xfer_memory() needs to do the write operation in chunks of words,
and these chunks must be 4byte aligned. So when do step 2, it creates a
3 words buffer, reads the word at Addr - 20 to get the first 2 bytes,
fills in the next 10 bytes, and then writes 3 words at Addr - 20.
So far, so good.

For the next write operation, child_xfer_memory() needs to write 8 bytes
at Addr - 26. Addr - 26 is not 4bytes aligned, so GDB decides to write
at Addr - 28. And to be able to write the full structure, GDB will need
to write 3 words. As before, it reads the first two bytes, and then
decides to read the last 2 bytes, before then filling in the rest.

Unfortunately, it used the wrong address for reading the trailing bytes.
This later causes a memory corruption on the string that we just wrote,
when we finally write the buffer into memory, which explains the problem
we've seen.

The attached patch fixes it. It has been tested on powerpc-aix version
4.3.2 and 5.1, and shows no regression. Given the fact that the C mode
uses malloc() to allocate its inferior memory, I was not too surprised
that the test results did not improve.

Ok to commit?

2003-05-31  J. Brobecker  <brobecker@gnat.com>

        * rs6000-nat.c (child_xfer_memory): Compute the right address when
        fetching the trailing bytes of the buffer we are about to write.

Thanks,
-- 
Joel

BTW: libiberty no longer builds on AiX 4.3.2, and I suspect on any AiX 4.x.
I think I have the proper fix for it, will send it shortly, after I have
tested it on 5.x.

Attachment: rs6000-nat.c.diff
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]