Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Weird problem with pointer dereferencing

2 views
Skip to first unread message

Rui Maciel

unread,
Mar 25, 2010, 6:03:24 AM3/25/10
to
Consider the following test program:


<code>
#include <string.h>
#include <stdio.h>


struct buffer
{
#define BUFFER_SIZE 16
char buffer[BUFFER_SIZE];
char *p; /* cursor */
char *q; /* YYMARKER */
char *marker; /* token start marker */
char *limit; /* limit marker */
};

void fill(FILE *file, struct buffer *b)
{
if(feof(file))
{
}
else if(b->p > b->limit - 10)
{
memmove(b->buffer,b->marker, b->limit - b->marker);
b->limit = b->buffer + (b->limit - b->marker) + fread(b->buffer + (b->limit
- b->marker),sizeof(char),BUFFER_SIZE-(b->limit-b->marker),file);
b->p = b->buffer + (b->p - b->marker);
b->marker = b->buffer;
*b->limit = '\0'; // <----- offending line
}
}


int main(void)
{
struct buffer b = {.p = b.buffer+BUFFER_SIZE, .q= b.buffer+BUFFER_SIZE, .marker =
b.buffer+BUFFER_SIZE, .limit = b.buffer+BUFFER_SIZE};

fill(stdin, &b);

return 0;
}
</code>


I've noticed that the pointer dereferencing done at the marked offending line not only sets
*b->limit to '\0' but also has the nasty side effect of screwing up with the address
pointed to by b->p. For example, running the example code on GDB does the following:


<gdb output>
23 b->limit = b->buffer + (b->limit - b->marker) + fread(b->buffer +
(b->limit - b->marker),sizeof(char),BUFFER_SIZE-(b->limit-b->marker),file);
(gdb)
asdf asdf asdf adsf
24 b->p = b->buffer + (b->p - b->marker);
(gdb) n
25 b->marker = b->buffer;
(gdb) n
26 *b->limit = '\0'; // <----- offending line
(gdb) print *b
$1 = {buffer = "asdf asdf asdf a", p = 0x7fffffffdce0 "asdf asdf asdf
a\340\334\377\377\377\177", q = 0x7fffffffdcf0 "\340\334\377\377\377\177",
marker = 0x7fffffffdce0 "asdf asdf asdf a\340\334\377\377\377\177", limit =
0x7fffffffdcf0 "\340\334\377\377\377\177"}
(gdb) n
28 }
(gdb) print *b
$2 = {buffer = "asdf asdf asdf a", p = 0x7fffffffdc00 "\021 d\r", q = 0x7fffffffdcf0 "",
marker = 0x7fffffffdce0 "asdf asdf asdf a", limit = 0x7fffffffdcf0 ""}
</gdb output>


So, is this supposed to happen? I was expecting that the pointer dereference would only
change the value stored in the memory address pointed to by b->limit. Why is that memory
dereferencing screwing up with b->p?


Thanks in advance,
Rui Maciel

Branimir Maksimovic

unread,
Mar 25, 2010, 6:55:13 AM3/25/10
to
On Thu, 25 Mar 2010 10:03:24 +0000
Rui Maciel <rui.m...@gmail.com> wrote:

> Consider the following test program:
>

....


>
> So, is this supposed to happen? I was expecting that the pointer
> dereference would only change the value stored in the memory address
> pointed to by b->limit. Why is that memory dereferencing screwing up
> with b->p?

Because probably there is where b->limit points to?

Greets!


--
http://maxa.homedns.org/

Sometimes online sometimes not


Alan Curry

unread,
Mar 25, 2010, 6:56:13 AM3/25/10
to
In article <4bab34ef$0$361$a729...@news.telepac.pt>,

Rui Maciel <rui.m...@gmail.com> wrote:
|struct buffer
|{
| #define BUFFER_SIZE 16
| char buffer[BUFFER_SIZE];
| char *p; /* cursor */
| char *q; /* YYMARKER */
| char *marker; /* token start marker */
| char *limit; /* limit marker */
|};
[...]

|(gdb) n
|26 *b->limit = '\0'; // <----- offending line
|(gdb) print *b
|$1 = {buffer = "asdf asdf asdf a", p = 0x7fffffffdce0 "asdf asdf asdf
|a\340\334\377\377\377\177", q = 0x7fffffffdcf0 "\340\334\377\377\377\177",
| marker = 0x7fffffffdce0 "asdf asdf asdf a\340\334\377\377\377\177", limit =
|0x7fffffffdcf0 "\340\334\377\377\377\177"}
|(gdb) n
|28 }
|(gdb) print *b
|$2 = {buffer = "asdf asdf asdf a", p = 0x7fffffffdc00 "\021 d\r", q =
|0x7fffffffdcf0 "",
|marker = 0x7fffffffdce0 "asdf asdf asdf a", limit = 0x7fffffffdcf0 ""}
|</gdb output>

Your struct is located at 0x7fffffffdce0. The first field, buffer, is also
located at 0x7fffffffdce0. Its size is 16. Your b->limit pointer is
0x7fffffffdcf0, also known as 0x7fffffffdce0+16 or &buffer[16]. It's outside
the bounds of the array. Dereferencing b->limit is a classic buffer overflow
error, and writing to it caused memory corruption elsewhere.

The "elsewhere" happened to be b->p because the p field immediately follows
the buffer, and there was no padding between them.

--
Alan Curry

Ike Naar

unread,
Mar 25, 2010, 7:06:43 AM3/25/10
to
In article <4bab34ef$0$361$a729...@news.telepac.pt>,
Rui Maciel <rui.m...@gmail.com> wrote:

You are writing outside the buffer; it is only BUFFER_SIZE characters
long, but you're writing a '\0' on top of the (BUFFER_SIZE+1)'st character.

Rui Maciel

unread,
Mar 25, 2010, 7:15:59 AM3/25/10
to
Alan Curry wrote:

> Your struct is located at 0x7fffffffdce0. The first field, buffer, is also
> located at 0x7fffffffdce0. Its size is 16. Your b->limit pointer is
> 0x7fffffffdcf0, also known as 0x7fffffffdce0+16 or &buffer[16]. It's
> outside the bounds of the array. Dereferencing b->limit is a classic
> buffer overflow error, and writing to it caused memory corruption
> elsewhere.
>
> The "elsewhere" happened to be b->p because the p field immediately
> follows the buffer, and there was no padding between them.

You are absolutely right. The dreaded "off-by-one" error... Shame on me.


Thanks for the help,
Rui Maciel

Morris Keesan

unread,
Mar 25, 2010, 1:44:37 PM3/25/10
to
On Thu, 25 Mar 2010 06:03:24 -0400, Rui Maciel <rui.m...@gmail.com>
wrote:


> void fill(FILE *file, struct buffer *b)
> {
> if(feof(file))
> {
> }
> else if(b->p > b->limit - 10)
> {

...
> fread(
...
> ,file);

In addition to the off-by-one error that caused the pointer problem you
were looking for, this code exhibits a very common misunderstanding of
end-of-file processing in C. feof(file) returns true when a PREVIOUS
attempt to read from the file has encountered an end of file condition.
If feof(file) returns false, this tells you nothing at all about whether
the file pointer is currently at the end of the file, causing the next
read to fail.
--
Morris Keesan -- mke...@post.harvard.edu

0 new messages