none
Неожиданное поведение библиотечных функций "fread" "fsetpos". RRS feed

  • Вопрос

  • Здравствуйте, проблема появляется при чтении("fread") данных в количестве равных размеру буфера для стрима(в дальнейшем РБС), в этом случае стрим не буферезируется(а судя по коду и логике должен был), и это приводит к тому, что пока мы будем читать из буферезированной области, мы будем читать какой-то мусор, на который ссылался изначально буфер. Файл открыт как бинарный("rb").

    Пример:
    const fpos_t newPos = 1000; // Рандомное значение
    const size_t count = 4096; // Размер буфера
    ...
    // буферезированная область [1000..5096]
    ...
    fsetpos( handle, &newPos  );
    fread( data, 1, count, handle ); // в data будут ожидаемые значения
    fsetpos( handle, &newPos  );
    fread( data, 1, count, handle ); // в data будет мусор
    ...
    const fpos_t nextPos = 2000; // остаемся в пределах буфера
    const size_t nextCount = 1000; // остаемся в пределах буфера
    fsetpos( handle, &nextPos );
    fread( data, 1, nextCount , handle ); // в data будет мусор

    Возможная проблема:
    Я немного посмотрел исходный код и проблема может крыться в fread.cpp:
    fread.cpp:146 "else if (remaining_bytes >= stream_buffer_size)" возможно достаточным будет сделать условие более строгим ">"
    также я смотрел fseek.cpp потенциальные проблемы могут быть и там при вычислении _ptr и _cnt для stream.

    Моя версия SDK: Windows Kits\10\Source\10.0.10240.0

    Буду признателен, если вы сообщите: о моем возможно неправильном использовании библиотеки; когда будет исправлена бага; в какой версии SDK проблемы не наблюдается.

    Спасибо.
    10 октября 2019 г. 13:43

Ответы

  • Попробуйте добавить проверку ошибок fsetpos/fread,  как-то так:

    #include <stdlib.h>
    #include <stdio.h>
    
    int main( int argc, char *argv[] )
    {
    	const fpos_t newPos = 1000; 
    	const size_t count = 4096; 
    	char data[count];
    	size_t readcount;
    	int result;
    
    	FILE* handle = fopen("D:\\Test\\File.txt","rb"); 
    
    	result = fsetpos( handle, &newPos  );
    	if(result!=0) printf("fsetpos failed: %d\n",result);
    	
    	readcount = fread( data, 1, count, handle ); 
    	if(readcount < count) {
    		result = ferror(handle);
    		if(result!=0) printf("fread failed: %d\n",result);
    	}
    	else {
    		printf("fread success: %d bytes read\n",(int)readcount);
    		printf("data: [%.20s]\n",data);
    	}
    	
    	const fpos_t nextPos = 2000; 
    	const size_t nextCount = 1000; 
    	result = fsetpos( handle, &nextPos );
    	if(result!=0) printf("fsetpos failed: %d\n",result);
    
    	readcount = fread( data, 1, nextCount , handle ); 
    	if(readcount < nextCount) {
    		result = ferror(handle);
    		if(result!=0) printf("fread failed: %d\n",result);		
    	}
    	else {
    		printf("fread success: %d bytes read\n",(int)readcount);
    		printf("data: [%.20s]\n",data);
    	}
    	fclose(handle);
        getchar();
    }

    И покажите, что выведется у вас. 

    >Буду признателен, если вы сообщите: о моем возможно неправильном использовании библиотеки; когда будет исправлена бага; в какой версии SDK проблемы не наблюдается.

    Universal CRT - компонент Windows, который обновляется вместе с Windows Update, поэтому тут скорее важна версия Windows, чем SDK. SDK предоставляет лишь заголовочные файлы и библиотеки импорта. Но я лично сомневаюсь, что в функции fread Universal CRT может быть баг - это было бы слишком болезненно очевидно, так как >50% программ зависят от нее и соответственно работали бы работали неправильно.

    13 октября 2019 г. 8:13