r-lib / lobstr

Understanding complex R objects with tools similar to str()
https://lobstr.r-lib.org/
Other
303 stars 27 forks source link

obj_size causing segfault with an example from Advanced R #29

Closed dpritchLibre closed 6 years ago

dpritchLibre commented 6 years ago

When I try to run the example in Exercise 2 of Section 2.4.1 in the second edition of Advanced R, I am getting a segfault on a call to lobstr::obj_size. The example code is shown below. I would be happy to work on a fix if it turns out to not be just a dependency issue or something similar, and given some direction.

devtools::session_info("lobstr")
#> ─ Session info ──────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 3.4.4 (2018-03-15)
#>  os       Ubuntu 16.04.5 LTS          
#>  system   x86_64, linux-gnu           
#>  ui       X11                         
#>  language en_US                       
#>  collate  en_US.UTF-8                 
#>  ctype    en_US.UTF-8                 
#>  tz       America/New_York            
#>  date     2018-11-17                  
#> 
#> ─ Packages ──────────────────────────────────────────────────────────────
#>  package * version date       lib source        
#>  crayon    1.3.4   2017-09-16 [1] CRAN (R 3.4.1)
#>  lobstr    1.0.0   2018-11-04 [1] CRAN (R 3.4.4)
#>  Rcpp      1.0.0   2018-11-07 [1] CRAN (R 3.4.4)
#>  rlang     0.3.0.1 2018-10-25 [1] CRAN (R 3.4.4)
#> 
#> [1] /home/dpritch/R/x86_64-pc-linux-gnu-library/3.4
#> [2] /usr/local/lib/R/site-library
#> [3] /usr/lib/R/site-library
#> [4] /usr/lib/R/library

x <- list(mean, sd, var)
lobstr::obj_size(x)
#>  *** caught segfault ***
#> address 0x2, cause 'memory not mapped'
#> 
#> Traceback:
#>  1: .Call(`_lobstr_obj_size_`, objects, base_env, sizeof_node, sizeof_vector)
#>  2: obj_size_(dots, env, size_node(), size_vector())
#>  3: lobstr::obj_size(x)
#>  4: eval(expr, envir, enclos)
#>  5: eval(expr, envir, enclos)
#>  6: withVisible(eval(expr, envir, enclos))
#>  7: withCallingHandlers(withVisible(eval(expr, envir, enclos)), warning = wHandler,     error = eHandler, message = mHandler)
#>  8: doTryCatch(return(expr), name, parentenv, handler)
#>  9: tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 10: tryCatchList(expr, classes, parentenv, handlers)
#> 11: tryCatch(expr, error = function(e) {    call <- conditionCall(e)    if (!is.null(call)) {        if (identical(call[[1L]], quote(doTryCatch)))             call <- sys.call(-4L)        dcall <- deparse(call)[1L]        prefix <- paste("Error in", dcall, ": ")        LONG <- 7
hadley commented 6 years ago

I also see this locally

hadley commented 6 years ago

Minimal reprex is obj_size(mean)

hadley commented 6 years ago

But doesn't crash for any of these:

obj_size(sum)
obj_size(function(x, ...) UseMethod("mean"))

Also crashes on obj_size(sd) (so not related to S3-ness)

hadley commented 6 years ago

Crashes when iterating through BODY(x):

  case DOTSXP:
  case LISTSXP:
  case LANGSXP:
  case BCODESXP:
    if (x == R_MissingArg) // Needed for DOTSXP
      break;

    for(SEXP cons = x; cons != R_NilValue; cons = CDR(cons)) {
      if (cons != x)
        size += sizeof_node;
      size += obj_size_tree(TAG(cons), base_env, sizeof_node, sizeof_vector, seen);
      size += obj_size_tree(CAR(cons), base_env, sizeof_node, sizeof_vector, seen);
    }

But obj_size(body(sd)) works

hadley commented 6 years ago

Ah body() uses BODY_EXPR() while obj_size() uses BODY().

hadley commented 6 years ago

Because the code for iterating over the bytecode (which BODY() returns but BODY_EXPR() does not) was broken.