[Toybox] tac issues and tests

Rob Landley rob at landley.net
Thu Dec 20 23:05:18 PST 2012


On 12/15/2012 01:06:21 PM, Elie De Brauwer wrote:
> Hi Rob and all,
> 
> I've been playing around with 'tac'. And as a result you can find two  
> patches
> in attach. The first one removes some code from tac for that simple  
> reason that
> the tac toy contains some logic (including a strlen) to remove a  
> trailing \n
> (if present). But this \n is the seperator which get_line()  
> internally passes
> to get_rawline() and that newline is already removed in get_line().

Sorry for the delay answering, bit crazy around here. I merged the  
patches you sent, and I think I'm caught up now?

> Next to this you can find some test for tac which are based upon the  
> cat tests. I
> have however found two problems I'd like to throw in the group.
> 
> Problem 1:
> On my system:
> edb at lapedb:~/today$ echo -ne "abc\ndef" | tac
> defabc\n
> tac in toybox:
> edb at lapedb:~/edb-stuff/toybox/toybox$ echo -ne "abc\ndef" | ./toybox  
> tac
> def\n
> abc\n
> (I added the \n here for visibility). This however cannot be  
> trivially fixed because
> of the implicit separator in get_line() as stated above. Nevertheless  
> the output of
> the 'default' tac is such a corner case that probably no sane human  
> being would use
> it that way (I hope).

We should make no newline at end of file work. I note that get_line()  
dates back to before posix-2008, which standardized getline() and  
getdelim(). It persists because it uses a file descripter instead of a  
FILE *, but that's not necessarily enough justification. Taking another  
look at this is on my todo list, but pretty far down.

In any case, it's a wrapper around get_rawline(), which we should  
probably be using here.

> Problem 2:
> cat has a test which writes to /dev/full to see if the error gets  
> caught. cat however
> doesn't use xwrite but uses xputs to put its output (also a cause for  
> problem 1). But
> take a look at the following strace output of
> 
> echo "boe" | strace ./toybox tac > /dev/full
> 
> read(0, "b", 1)                         = 1
> read(0, "o", 1)                         = 1
> read(0, "e", 1)                         = 1
> read(0, "\n", 1)                        = 1
> read(0, "", 1)                          = 0
> fstat64(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 7), ...}) = 0
> ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfb6ae50) = -1 ENOTTY  
> (Inappropriate ioctl for device)
> mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,  
> -1, 0) = 0xb773d000
> write(1, "boe\n", 4)                    = -1 ENOSPC (No space left on  
> device)
> exit_group(0)                           = ?
> 
> True, xputs uses puts which ends up calling write() which returns -1  
> but this does
> not ripple through to puts() and thus the error condition in xputs()  
> doesn't trigger
> (it just happily return a '4').

Wow. That sounds like a libc bug? (Which libc are you using?)

> So in order to fix the issues above I would make 'tac' more like  
> 'cat', which would
> probably mean not using get_line() but using get_rawline() (and thus  
> reintroducing
> what I threw out in my patch ;-) ), not removing the newline and  
> using xwrite()
> (eventually storing the length somewhere) to write the output. This  
> would still not
> solve the root problem of xputs() not triggering when write throws  
> and ENOSPC at you.
> 
> What do you guys think ?

If xputs() doesn't work we should redo xputs() not to use puts(). I've  
got it because puts is a common case that shaves several bytes vs  
xprintf("%s\n", str), but it needs to work properly.

Rob
 1356073518.0


More information about the Toybox mailing list