diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2014-06-02 09:57:28 -0400 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 2014-06-03 06:36:20 -0400 |
commit | 43e5477e1cb9b5aed5748aeeb8d72fe147e673a7 (patch) | |
tree | 602c7ef697c541ee986d1bcaee14b399c5485a3a /perlio.c | |
parent | cf6e31e92ce25aab729563d4e1451cbf65e5138b (diff) | |
download | perl-43e5477e1cb9b5aed5748aeeb8d72fe147e673a7.tar.gz |
38d96942 missed a side-effect in PerlIO_open flags parsing.
The mode++ was essential in allowing 'rb' for the PerlIO_open() flags.
Without the mode++ the 'b' was left unprocessed and this caused
the oflags to become bogus.
Compress::Bzip2 caught this: https://rt.perl.org/Ticket/Display.html?id=122012
(also Unicode::Map8, Text::Scan, and otehrs)
While doing this, realized that for the "O_BINARY versus O_TEXT" it's
probably the clearest to test for the non-zero-ness of those two flags.
(Is there any "unit testing" of PerlIO? In this case it would be:
PerlIO_open -> PerlIO_openn -> PerlIOBuf_open -> PerlIOUnix_open ->
PerlIOUnix_oflags with mode of "rb")
Diffstat (limited to 'perlio.c')
-rw-r--r-- | perlio.c | 43 |
1 files changed, 31 insertions, 12 deletions
@@ -199,10 +199,12 @@ PerlIO_intmode2str(int rawmode, char *mode, int *writing) mode[ix++] = '+'; } } -#ifdef PERLIO_BINARY_AND_TEXT_DIFFERENT_AND_EFFECTIVE +#if O_BINARY != 0 + /* Unless O_BINARY is different from zero, bit-and:ing + * with it won't do much good. */ if (rawmode & O_BINARY) mode[ix++] = 'b'; -#endif +# endif mode[ix] = '\0'; return ptype; } @@ -2529,25 +2531,42 @@ PerlIOUnix_oflags(const char *mode) oflags |= O_WRONLY; break; } -#ifdef PERLIO_BINARY_AND_TEXT_DIFFERENT_AND_EFFECTIVE - if (*mode == 'b') { - oflags |= O_BINARY; + + /* XXX TODO: PerlIO_open() test that exercises 'rb' and 'rt'. */ + + /* Unless O_BINARY is different from O_TEXT, first bit-or:ing one + * of them in, and then bit-and-masking the other them away, won't + * have much of an effect. */ + switch (*mode) { + case 'b': +#if O_TEXT != O_BINARY + oflags |= O_BINARY; oflags &= ~O_TEXT; - mode++; - } - else if (*mode == 't') { +#endif + mode++; + break; + case 't': +#if O_TEXT != O_BINARY oflags |= O_TEXT; oflags &= ~O_BINARY; - mode++; - } - else { +#endif + mode++; + break; + default: +# if O_BINARY != 0 + /* bit-or:ing with zero O_BINARY would be useless. */ /* * If neither "t" nor "b" was specified, open the file * in O_BINARY mode. + * + * Note that if something else than the zero byte was seen + * here (e.g. bogus mode "rx"), just few lines later we will + * set the errno and invalidate the flags. */ oflags |= O_BINARY; +# endif + break; } -#endif if (*mode || oflags == -1) { SETERRNO(EINVAL, LIB_INVARG); oflags = -1; |