Opened 5 years ago

Last modified 5 months ago

#7161 new bug

hSetNewlineMode and hSetEncoding can be performed on closed and semi-closed handles

Reported by: duncan Owned by:
Priority: normal Milestone:
Component: Core Libraries Version: 7.6.1-rc1
Keywords: Cc: core-libraries-committee@…, ekmett
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description (last modified by thomie)

The hSetNewlineMode and hSetEncoding functions from GHC/IO/Handle.hs do not check that the Handle is in an open mode. It is possible to use them on closed handles. hSetEncoding on a closed Handle triggers a segfault. Similarly, the operations are also both possible on semi-closed handles, and given the way hGetContents is implemented, this will affect the result of hGetContents which is clearly against the intention of the hGetContents/semi-closed stuff.

Both functions use the withAllHandles__ helper. Unlike similar helpers like wantReadableHandle_ this one doesn't do any handle mode checking.

Additionally, hSetBuffering and hSetBinaryMode mode also use the withAllHandles__ pattern and don't obviously check for an open handle but I've not verified this.

Change History (11)

comment:1 Changed 5 years ago by igloo

difficulty: Unknown
Milestone: 7.8.1

Can you give us a way to reproduce the segfault please? I tried:

module Main (main) where

import System.IO

main :: IO ()
main = do h <- openFile "tmp" WriteMode
          hPutStrLn h "Test"
          hClose h
          hSetEncoding h utf8
          hSetEncoding h utf32
          hSetEncoding h utf8
          print h
$ ghc --make q
$ ./q
{handle: tmp}

but got no segfault.

comment:2 Changed 3 years ago by thoughtpolice

Milestone: 7.8.37.10.1

Moving to 7.10.1

comment:3 Changed 3 years ago by thoughtpolice

Component: libraries/baseCore Libraries
Owner: set to ekmett

Moving over to new owning component 'Core Libraries'.

comment:4 Changed 2 years ago by thomie

Cc: core-libraries-committee@… added
Status: newinfoneeded

comment:5 Changed 2 years ago by thoughtpolice

Milestone: 7.10.17.12.1

Moving to 7.12.1 milestone; if you feel this is an error and should be addressed sooner, please move it back to the 7.10.1 milestone.

comment:6 Changed 21 months ago by thoughtpolice

Milestone: 7.12.18.0.1

Milestone renamed

comment:7 Changed 20 months ago by thomie

Owner: ekmett deleted

comment:8 Changed 18 months ago by thomie

Cc: ekmett added
Description: modified (diff)
Status: infoneedednew

With or without segfaults, this could be fixed.

comment:9 Changed 16 months ago by thomie

Milestone: 8.0.1

comment:10 Changed 5 months ago by joeyhess

I reproduced this bug in the wild today. Here is my test case:

import GHC.IO.Encoding
import System.IO

main = do
        e <- getFileSystemEncoding
        hClose stdin
        hSetEncoding stdin e

ghc 8.0.1 on Linux.

For me, the crash only occurs with LANG=C. With my usual locale of en_US.utf8 there is no crash. Perhaps this is why there was a problem reproducing it.

Last edited 5 months ago by joeyhess (previous) (diff)

comment:11 Changed 5 months ago by joeyhess

And here is the segfault info:

*** Error in `./foo': double free or corruption (top): 0x0000000000b7b620 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bcb)[0x7f042ba4bbcb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76fa6)[0x7f042ba51fa6]
/lib/x86_64-linux-gnu/libc.so.6(+0x7779e)[0x7f042ba5279e]
/lib/x86_64-linux-gnu/libc.so.6(+0x21226)[0x7f042b9fc226]
/lib/x86_64-linux-gnu/libc.so.6(iconv_close+0xf)[0x7f042b9fbabf]
./foo[0x40ef80]
Note: See TracTickets for help on using tickets.