<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
> 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!
Sometimes online sometimes not
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
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.
> 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
> 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