Ticket UUID: | 2176669 | |||
Title: | Strange seek bug | |||
Type: | Bug | Version: | obsolete: 8.4.19 | |
Submitter: | nobody | Created on: | 2008-10-18 11:57:20 | |
Subsystem: | 25. Channel System | Assigned To: | andreas_kupries | |
Priority: | 8 | Severity: | ||
Status: | Closed | Last Modified: | 2009-12-10 06:05:51 | |
Resolution: | Duplicate | Closed By: | ||
Closed on: | ||||
Description: |
I've got strange seek behavior executing this simple script (Windows XP, tcl 8.4.19/8.5.2/8.6a1): --- exp.tcl --- set fd [open hash.db r+] seek $fd 100 puts [tell $fd] puts -nonewline $fd 0 puts [tell $fd] read $fd 2 seek $fd 0 puts [tell $fd] --- Result is: 100 101 error during seek on "filea3bf40": bad address in system call argument while executing "seek $fd 0" (file "exp.tcl" line 8) ------------ It seems that it originates from here: ----- tclIO.c ----- ... In Tcl_Seek: /* * Compute how much input and output is buffered. If both input and output * is buffered, cannot compute the current position. */ inputBuffered = Tcl_InputBuffered(chan); outputBuffered = Tcl_OutputBuffered(chan); if ((inputBuffered != 0) && (outputBuffered != 0)) { Tcl_SetErrno(EFAULT); return Tcl_LongAsWide(-1); } -------- So, [flush]-ing channel before seeking helps. I didn't find this documented anywhere. Moreover, as Alexandre Ferrieux said, [seek] is documented to flush the output side. | |||
User Comments: |
andreas_kupries added on 2009-12-10 06:05:33:
This artifact has been marked as a duplicate of artifact 2901998 with reason: Same thing internally, buffered output was not flushed before read ferrieux added on 2009-11-22 17:51:02: Previous comment now promoted to a bug by itself: 2901998. The reason is that it is simpler and more spectacular. Note that the fix I propose (assuming the potential incompatibility is validated as benign) would solve both. ferrieux added on 2009-11-22 06:04:02: Looking in detail at your example, I'm a bit surprised by yet another effect of this internal I/O conflict: after the 1-byte [puts], if we ask [tell] (which your example doesn't do), we get 1 of course. But then, at script level, how do we explain the fact that the subsequent [read] starts from the beginning of the file ? In other words, if we forget about the underlying OS file position and concentrate on the only Tcl-visible thing which is what [tell/seek] manipulate, it seems only logical to assume it is *both* a read and write pointer (otherwise we'd need extra API to separate them). Then after writing one byte we're at position 1, and the subsequent [read 2] should read from that position, and hence return the 2nd and 3rd byte of the file ("0a" here). Of course the implication of such a semantics is that a read might incur a flush (otherwise costly overlap computations are needed). So what ? Apart from the POTENTIAL INCOMPATIBILITY, what's wrong with such a simplified "Tcl r/w file pointer" concept ? andreas_kupries added on 2009-11-21 04:35:18: I believe this is a limitation which we should just document somewhere (seek ?), with example. andreas_kupries added on 2009-11-21 02:49:35: I have attached 2 scripts, one generating the test input file for the other. The other, wr.tcl, should explain why having both input and output buffered is a bad thing regarding seek and tell, i.e. why they are reported as error. See the comments in the script. andreas_kupries added on 2009-11-21 02:48:01: File Added - 351874: wr.tcl andreas_kupries added on 2009-11-21 02:47:12: File Added - 351873: maketestfile.tcl andreas_kupries added on 2009-11-21 02:03:20: Notes ... Regarding "[seek] is documented to flush the output side. " Yes. That happens too. It happens quite a bit after the check which fails here. ferrieux added on 2008-10-21 06:28:49: File Added - 298169: seek.diff ferrieux added on 2008-10-21 06:28:40: Oops I forgot both to login and to attach the file, sorry ;-) [email protected] added on 2008-10-21 05:37:28: The attached patch fixes that strange behavior *and* passes the test suite. The idea is that the check was useless because of the DiscardInputQueued(). The important part which I kept is the if (mode == SEEK_CUR) { offset -= inputBuffered; } What is unclear to me though, is the reason for this check... ferrieux added on 2008-10-20 04:54:44: Looking at the code in Tcl_Seek, there's something I don't understand: a few lines below the above test against simultaneous input and output data buffered, there is: DiscardInputQueued(statePtr, 0); whose effect is to guaranteed nothing's left in the input buffer chain. So, why not do it first, and avoid the error ? |