From henrik.bengtsson at gmail.com  Sun Oct 30 19:38:07 2016
From: henrik.bengtsson at gmail.com (Henrik Bengtsson)
Date: Sun, 30 Oct 2016 11:38:07 -0700
Subject: [Rd] closeAllConnections() can really mess things up
Message-ID: <CAFDcVCTOvn4mc9Xva8FMP-hMiR-p2thQvKVs7ynFFCspDy6Adg@mail.gmail.com>

This is what I get on R 3.3.1 on Linux:

> con1 <- textConnection("foo1", open = "w")
> print(con1)
     description            class             mode             text
          "foo1" "textConnection"              "w"           "text"
          opened         can read        can write
        "opened"             "no"            "yes"

> closeAllConnections()
> con2 <- textConnection("foo2", open = "w")

## Hmm... at this point, con1 point to con2.

> print(con1)
     description            class             mode             text
          "foo2" "textConnection"              "w"           "text"
          opened         can read        can write
        "opened"             "no"            "yes"

> all.equal(con2, con1)
[1] TRUE

Hmm... that looks it could potentially mess up things badly if some
code / user calls closeAllConnections(), then other connections are
opened after that, and then there's code (e.g. via promises or
finalizers) that tries to write to the original connections (resulting
in writing to the new ones).

I'm not sure how one can protect oneself against this.  One approach
that could lower the risk for mistakes is to record a checksum for the
connection (think digest::digest(summary(con1))) when the connection
is first opened and then each time one tried to read or write to the
connect, one validate against this again.

I can see how this could happen if each connection is referenced via
an integer index internally.

I discovered this in a case where the R session terminates (for
unknown reasons) and then calls sys.save.image().  sys.save.image()
calls closeAllConnections() and then save.image().   The latter
triggered promises / delayed assignments to be resolved.  Then each of
those tries to access their previously assigned connections.  At this
point, those are now all closed, but the promises doesn't know and
instead tries to read their connections.  At least the first one will
try to access the now only open connection, which is the one
save.image() opened.  In my case, they tried to read so they failed.

/Henrik



[Rd] closeAllConnections() can really mess things up
Henrik Bengtsson