Update: This document is preserved for legacy apps only. We recommend you use the odbc package and update your ODBC drivers to the latest release. If you are a professional customer, we recommend using the RStudio Professional Drivers along with the odbc package. You should not have segfaults if your software is up to date.
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)
Comments