From maechler at stat.math.ethz.ch  Tue Dec  6 18:49:05 2016
From: maechler at stat.math.ethz.ch (Martin Maechler)
Date: Tue, 6 Dec 2016 18:49:05 +0100
Subject: [Rd] segfault with POSIXlt zone=NULL zone=""
In-Reply-To: <CAPPM_gRX8zWeDk=jiL2=goqFhbcw12OCW0NXDbnCB9Er6hTdVA@mail.gmail.com>
References: <20161206123720.GA21285@ofb.net>
	<CAPPM_gRX8zWeDk=jiL2=goqFhbcw12OCW0NXDbnCB9Er6hTdVA@mail.gmail.com>
Message-ID: <22598.64017.586103.632493@stat.math.ethz.ch>

>>>>> Joshua Ulrich <josh.m.ulrich at gmail.com>
>>>>>     on Tue, 6 Dec 2016 09:51:16 -0600 writes:

    > On Tue, Dec 6, 2016 at 6:37 AM,  <frederik at ofb.net> wrote:
    >> Hi all,
    >> 
    >> I ran into a segfault while playing with dates.
    >> 
    >> $ R --no-init-file
    >> ...
    >> > library(lubridate); d=as.POSIXlt(floor_date(Sys.time(),"year")); d$zone=NULL; d$zone=""; d
    >> 
    > If you're asking about a bug in R, you should provide a *minimal*
    > reproducible example (i.e. one without any package dependencies).
    > This has nothing to do with lubridate, so you can reproduce the
    > behavior with:

    > d <- as.POSIXlt(Sys.time())
    > d$zone <- NULL
    > d$zone <- ""
    > d

    [..........]
    
    >> Hope I'm not doing something illegal...
    >> 
    > You are.  You're changing the internal structure of a POSIXlt object
    > by re-ordering the list elements.  You should not expect a malformed
    > POSIXlt object to behave as if it's correctly formed.  You can see
    > it's malformed by comparing it's unclass()'d output.

    > d <- as.POSIXlt(Sys.time())
    > unclass(d)  # valid POSIXlt object
    > d$zone <- NULL
    > d$zone <- ""
    > unclass(d)  # your malformed POSIXlt object

Indeed, really illegal, i.e. "against the law" ... ;-)

Thank you, Joshua!

Still, if R segfaults without the user explicitly
calling .Call(), .Internal()  or similar -- as here --
we usually acknowledge there *is* a bug in R .. even if it is
only triggered by a users "illegal" messing around.

an MRE for the above, where I really only re-order the "internal" list:

d <- as.POSIXlt("2016-12-06"); dz <- d$zone; d$zone <- NULL; d$zone <- dz; f <- format(d)

>  *** caught segfault ***
> address 0x80000020, cause 'memory not mapped'

> Traceback:
>  1: format.POSIXlt(d)
>  2: format(d)

The current code is "optimized for speed" (not perfectly), and
a patch should hopefully address the C code.

Note that a smaller MRE -- which does *not* re-order, but just
invalidate the time zone is

  d <- as.POSIXlt("2016-12-06"); d$zone <- 1; f <- format(d)

------

I have now committed a "minimal" patch (to the C code) which for
the above two cases gives a sensible error rather than a
seg.fault :

  > d <- as.POSIXlt("2016-12-06"); d$zone <- 1 ; f <- format(d)
  Error in format.POSIXlt(d) : 
    invalid 'zone' component in "POSIXlt" structure

  > d <- as.POSIXlt("2016-12-06"); dz <- d$zone; d$zone <- NULL; d$zone <- dz; f <- format(d)
  Error in format.POSIXlt(d) : 
    invalid 'zone' component in "POSIXlt" structure
  > 

I guess that it should still be possible to produce a segfault
with invalid 'POSIXlt' structures though.

Martin



[Rd] segfault with POSIXlt zone=NULL zone=""
Martin Maechler