#primAtEnd: bug? (was: Re: [squeak-dev] Caching MultiByteFileStream bug?)

Levente Uzonyi leves at elte.hu
Thu Apr 1 14:59:29 UTC 2010


On Tue, 30 Mar 2010, Levente Uzonyi wrote:

> On Mon, 29 Mar 2010, Andreas Raab wrote:
>
>> Hi Levente -
>> 
>> Could you check the failure of FileStreamTest>>testNextChunkOutOfBounds? 
>> This looks like it might be a problem with caching file stream behavior. If 
>> it's not (i.e., the infinite recursion is the 'expected' behavior) can we 
>> add something that addresses the issue?
>
> Seems like #primAtEnd: doesn't answer true if position is out of bounds and 
> there are no more bytes to read:

I realized that even if I push the changes for #basicUpTo: and friends 
there may be arbitrary code that assumes that #atEnd will return true if 
there's nothing more to read. How should this issue be fixed?

One solution is to change StandardFileStream >> #atEnd to something like 
this:

atEnd
 	"Answer whether the receiver is at its end.  "

 	collection ifNotNil: [
 		position < readLimit ifTrue: [ ^false ] ].
 	^(self primSizeNoError: fileID)
 		ifNil: [ true ]
 		ifNotNil: [ :size | size <= self position ]

But this means that #primAtEnd: is not used at all, so it's just a 
workaroud.

The other option is to change the VM code. This means changing == to >= 
like this:

For unix and mac (cross):

sqInt sqFileAtEnd(SQFile *f) {
 	/* Return true if the file's read/write head is at the end of the file. */

 	if (!sqFileValid(f)) return interpreterProxy->success(false);
 	return ftell(getFile(f)) >= getSize(f);
}

For windows:

sqInt sqFileAtEnd(SQFile *f) {
   win32FileOffset ofs;
   /* Return true if the file's read/write head is at the end of the file. */
   if (!sqFileValid(f)) FAIL();
   ofs.offset = 0;
   ofs.dwLow = SetFilePointer(FILE_HANDLE(f), 0, &ofs.dwHigh, FILE_CURRENT);
   return ofs.offset >= sqFileSize(f);
}

What do you think?


Levente

>
> FileStream forceNewFileNamed: 'testFileStreamAtEnd' do: [ :file |
> 	file position: 1000.
> 	self assert: file next isNil.
> 	self assert: file atEnd ].
>
> Read buffering doesn't affect this behavior:
>
> FileStream forceNewFileNamed: 'testFileStreamAtEnd' do: [ :file |
> 	file disableReadBuffering.
>        file position: 1000.
>        self assert: file next isNil.
>        self assert: file atEnd ].
>
> Really:
>
> FileStream forceNewFileNamed: 'testFileStreamAtEnd' do: [ :file |
> 	| fileID buffer1 count |
> 	file disableReadBuffering.
> 	file position: 1000.
> 	fileID := file instVarNamed: #fileID.
> 	buffer1 := String new: 1.
> 	count := file primRead: fileID into: buffer1 startingAt: 1 count: 1.
> 	self assert: count = 0.
> 	self assert: (file primAtEnd: fileID) ].
>
> We can work around this issue with StandardFileStream >> #upTo: and friends 
> (by replacing the old code which uses recursion and is pretty inefficient 
> btw), but I think #atEnd should answer true in this case.
>
>
> Levente
>
>> 
>> Thanks,
>>  - Andreas
>> 
>> 
>
>



More information about the Squeak-dev mailing list