2014-01-07 2 views
0

Сегодня я обнаружил патч ядра Linux в дереве ext4.Расчет указателя void в gcc

Отсутствующих литые означает, что, когда мы усечение файла, который находится менее чем 60 байт, мы не trunate неправильной области памяти, а на самом деле мы можем в конечном итоге усечение следующего инода в inode table, или хуже еще, некоторая другая структура данных ядра.

  • Адреса-Coverity-Id: # 751987
  • Подпись-офф-на: "Теодор Ts'o"
  • Cc: [email protected]

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 ? 

Примечание. i_block's Тип - массив __le32. Тип i_size длинный длинный. Мой вопрос: есть ли в старой версии расчет на основе 4 байтов, а в новой версии - расчет на основе 1 байта? Правильно ли я понимаю?

+0

«Тип' '' '' 'i_block'' '' '' '' '' '' Не соответствует http://lxr.free-electrons.com/source/fs/ext4/ext4.h#L650 Согласно этой странице, type - «массив u32». –

+0

Вы имеете в виду 'i_block' - массив' u32', правильно? Это очень важно. – ugoren

+0

Патч недействителен C, поскольку выполнение арифметики указателя на 'void *' типизированном указателе не определяется стандартом C. Патч должен был бы быть заменен на 'char *'. – alk

ответ

4

Итак, давайте возьмем исходный код и сделаем его очень ясным для читателей. Если мы сделаем это, то мы смотрим на следующие две части кода:

  1. Исходный код:

    __le32 *p = (void *) ext4_raw_inode(&is.iloc)->i_block; 
    memset(p + i_size, 0, EXT4_MIN_INLINE_DATA_SIZE - i_size); 
    
  2. Новый код:

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

Теперь довольно ясно, что значение p + i_size будет отличаться в зависимости от типа p, который этот pa tch зафиксировано.

+1

Я чувствую, что стоит упомянуть, что выполнение арифметики на указателях «void» недействительно C, но расширение gcc. – alk

+0

И говорит, что арифметика работает так, как если бы она была char * (то есть она продвигает адрес через байты i_size здесь) – vonbrand

Смежные вопросы