BufBills
BufBills

Reputation: 8103

C void pointer calculation in gcc

Today I spotted a Linux kernel patch in ext4 tree.

A missing cast means that when we are truncating a file which is less than 60 bytes, we don't trunate the wrong area of memory, and in fact we can end up truncating the next inode in the inode table, or worse yet, some other kernel data structure.


 fs/ext4/inline.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index c417e52..ed29e72 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1928,9 +1928,11 @@ void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
                }

                /* Clear the content within i_blocks. */
-               if (i_size < EXT4_MIN_INLINE_DATA_SIZE)
-                       memset(ext4_raw_inode(&is.iloc)->i_block + i_size, 0,
-                                       EXT4_MIN_INLINE_DATA_SIZE - i_size);
+               if (i_size < EXT4_MIN_INLINE_DATA_SIZE) {
+                       void *p = (void *) ext4_raw_inode(&is.iloc)->i_block;
+                       memset(p + i_size, 0,
+                              EXT4_MIN_INLINE_DATA_SIZE - i_size);
+               }

                EXT4_I(inode)->i_inline_size = i_size <
                                        EXT4_MIN_INLINE_DATA_SIZE ?

Note. i_block's type is array of __le32. i_size's type is long long. My question is: is that the old version do calculation based on 4 bytes and new version does calculation based on 1 byte? Is my understanding correct?

Upvotes: 0

Views: 534

Answers (1)

Bill Lynch
Bill Lynch

Reputation: 81986

So, let's take the original code, and make the type of it very explicit to readers. If we do that, then we are looking at the following two pieces of code:

  1. The original code:

    __le32 *p = (void *) ext4_raw_inode(&is.iloc)->i_block;
    memset(p + i_size, 0, EXT4_MIN_INLINE_DATA_SIZE - i_size);
    
  2. The new code:

    void *p = (void *) ext4_raw_inode(&is.iloc)->i_block;
    memset(p + i_size, 0, EXT4_MIN_INLINE_DATA_SIZE - i_size);
    

Now, it's fairly clear that the value of p + i_size will be different depending on the type of p, which this patch has fixed.

Upvotes: 3

Related Questions