Support

Segmentation Faults (segfault) using RODBC with Shiny

Follow

We have found several instances where people running RODBC with Shiny on Linux have encountered segmentation faults (this means some code in the R process tries to read or write a forbidden memory address, causing the process to crash). Using RODBC from the R command line or from RStudio (not in a Shiny app) does not cause a crash.

While we do not currently know the underlying cause of the issue, it does appear to be related to the depth of the call stack.

What is the call stack?

For those of you that don’t know, the call stack is the list of functions that are executing at a given moment. If you have the following functions:

func_a <- function() {
  message("The stack depth is ", length(sys.frames()))
}
func_b <- function() {
  func_a()
}
func_c <- function() {
  func_b()
}

If you call func_a, you’ll see the message “The stack depth is 1”. But if you call func_c, the message will instead be “The stack depth is 3”. That’s because in the latter case, while func_a executes, the invocations of func_c and func_b have not completed; func_c waits for func_b to finish, and func_b waits for func_a to finish.

Call stack depth and Shiny

The previous example was quite simple. The Shiny package runs much more complicated code when serving even the simplest Shiny app.

Consider this simple app:

library(shiny)

message("The stack depth at the top of app.R is ", length(sys.frames()))

ui <- fluidPage(
  textOutput("out")
)

server <- function(input, output, session) {
  output$out <- renderText({
    message("The stack depth inside renderPrint is ", length(sys.frames()))
  })
}

shinyApp(ui, server)

When I run this app in my copy of RStudio Desktop, I get the messages:

  • The stack depth at the top of app.R is 4
  • The stack depth inside renderPrint is 83

The precise values you will get depends on the exact version of Shiny and also how the Shiny app was launched, but in all cases you should see similarly dramatic differences between the two values.

Call stack depth and RODBC

Generally, a stack depth of even several hundred frames is not inherently an issue. However, in the specific case of RODBC on Linux, it seems that if the first call to odbcDriverConnect happens at a call stack depth greater than 40 or so, you get a segmentation fault and the R process terminates.

However, if the first call to odbcDriverConnect happens with a shallower call stack depth, then any subsequent calls will succeed, even with very deep call stacks.

If your Shiny app is crashing with a segmentation fault, and it uses RODBC, the first step is to copy the line where you call odbcDriverConnect and paste it at the top level of your app. (Don’t forget to close the connection after you’ve opened it.) In a single-file app, this means toward the top of app.R (outside of the server function). In a ui.R/server.R app, this means you should make a global.R file in the same directory and put this line at the top.

For example, if your app looks like this:

library(shiny)

ui <- fluidPage(
  textOutput("out")
)

server <- function(input, output, session) {
  output$out <- renderText({
    con <- odbcDriverConnect("...")
    on.exit(odbcClose(con))
  })
}

shinyApp(ui, server)

Then the version with the workaround would look like this:

library(shiny)

# The next two lines are the workaround
con <- odbcDriverConnect("...")
odbcClose(con)

ui <- fluidPage(
  textOutput("out")
)

server <- function(input, output, session) {
  output$out <- renderText({
    con <- odbcDriverConnect("...")
    on.exit(odbcClose(con))
  })
}

shinyApp(ui, server)
Have more questions? Submit a request

Comments