-2

I am very confused with read() calls to get inotify events.

Here is the code:

#define EVENT_SIZE sizeof(inotify_event)
int fd = inotify_init();
int wd = inotify_add_watch(fd, dir, IN_MODIFY);
void* p = malloc(sizeof(EVENT_SIZE));
read(wd, p, (EVENT_SIZE + 10));

My test file is a.txt. The output after debug in gdb is:

{wd = 0, mask = 0, cookie = 0, len = 0, name = 0x558f05d002d0 ""}

Now, when I change the last line to read(fd, p, (EVENT_SIZE + 16));, the output that I get in gdb is:

{wd = 1, mask = 2, cookie = 0, len = 16, name = 0x5625cdd422d0 ".a.txt.swp"}

Q1. Why don't I get an overflow error because in both cases, I am writing more than the allocated buffer p?

Q2. If there is no error, then my first program should also work because my filename is less than 10, but it doesn't work and it only works with 16. What am I missing here?

compiler - g++ 9.3.0

os - ubuntu 20.04

Thank you.

BlueDiary9
  • 95
  • 2
  • 6
Abhinav Singh
  • 302
  • 3
  • 15

2 Answers2

0
  1. The behaviour of writing outside the boundaries of an array is undefined. Additionally, read reads up to the given number of bytes.
  2. ???
0

Q1

  1. You get a segfault, if your process attempts to access a memory address that does not belong to it.

  2. malloc - "Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2)."

  3. sbrk - "sbrk() increments the program's data space by increment bytes."

From 1., 2. and 3.: There is (probably) room left where you are able to write to, but the data (if any) after your allocated memory is definitely corrupted!

Q2

Read the documentation for inotify.

The meaning of the fields for inotify_event structure:

mask contains bits that describe the event that occurred (see below).

and

The len field counts all of the bytes in name, including the null bytes; the length of each inotify_event structure is thus sizeof(struct inotify_event)+len.

and

The name field is present only when an event is returned for a file inside a watched directory; it identifies the filename within the watched directory. This filename is null-terminated, and may include further null bytes ('\0') to align subsequent reads to a suitable address boundary.

and

The behavior when the buffer given to read(2) is too small to return information about the next event depends on the kernel version: in kernels before 2.6.21, read(2) returns 0; since kernel 2.6.21, read(2) fails with the error EINVAL. Specifying a buffer of size sizeof(struct inotify_event) + NAME_MAX + 1 will be sufficient to read at least one event.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11