Skip to content

Behavior change in cpp11::warning(fmt, args...) between 0.5.3 and 0.5.4 (clang only) #491

@jennybc

Description

@jennybc

readxl built against cpp11 0.5.4 segfaults at runtime when emitting a coercion warning. Built against cpp11 0.5.3 (same readxl source, same R,same compiler), it works. Demo below.

In readxl:

Problem observed in various settings:

Not reproduced on gcc anywhere (CRAN's gcc flavors and Linux/Windows GHA all pass). Not R-version-specific: R 4.5 and R 4.6 both crash with cpp11 0.5.4.

Demo notes:

  • R 4.5 on any clang platform. (cpp11 0.5.3 doesn't compile against R 4.6 —
    uses removed R_NamespaceRegistry — so R 4.5 is just where both versions
    build.)
  • readxl pinned to v1.4.5 (current CRAN release, predates the workaround).
    cpp11 is header-only, so the buggy templates are baked into readxl.so at
    install time; rebuild from source for each cpp11 version.
  • Build with -g -O0 for a clean, immediate segfault. At default -O2 the
    failure mode varies on macOS (indefinite hang). My ~/.R/Makevars:
CFLAGS=-g -O0 -Wall
CXXFLAGS=-g -O0 -Wall
CXX11FLAGS=-g -O0 -Wall
CXX14FLAGS=-g -O0 -Wall
CXX17FLAGS=-g -O0 -Wall
F77=gfortran
FC=gfortran

Here are the two different setups. It's important to specify ?source?reinstall in these pak calls to force recompilation and pick up the ambient cpp11.

# --- cpp11 0.5.3 ---
pak::pkg_install("cpp11@0.5.3")
pak::pkg_install("tidyverse/readxl@v1.4.5?source&reinstall")

# --- cpp11 0.5.4 ---
pak::pkg_install("cpp11")  # 0.5.4 from CRAN
pak::pkg_install("tidyverse/readxl@v1.4.5?source&reinstall")

This tickles the problem because we'll see some coercion warnings from forcing things to become logical.

library(readxl)

R.version.string
packageVersion("cpp11")
packageVersion("readxl")

read_excel(
  readxl_example("type-me.xlsx"),
  sheet = "logical_coercion",
  col_types = c("logical", "skip")
)

With cpp11 4.5.3, all is well. Notice the coercion warnings.

library(readxl)

R.version.string
#> [1] "R version 4.5.3 (2026-03-11)"
packageVersion("cpp11")
#> [1] '0.5.3'
packageVersion("readxl")
#> [1] '1.4.5'

read_excel(
  readxl_example("type-me.xlsx"),
  sheet = "logical_coercion",
  col_types = c("logical", "skip")
)
#> Warning: Expecting logical in A5 / R5C1: got a date
#> Warning: Expecting logical in A8 / R8C1: got 'cabbage'
#> # A tibble: 10 × 1
#>    `maybe boolean?`
#>    <lgl>
#>  1 NA
#>  2 FALSE
#>  3 TRUE
#>  4 NA
#>  5 TRUE
#>  6 FALSE
#>  7 NA
#>  8 TRUE
#>  9 FALSE
#> 10 FALSE

With cpp11 0.5.4, we see a segfault:

> library(readxl)
>
> R.version.string
[1] "R version 4.5.3 (2026-03-11)"
> packageVersion("cpp11")
[1] '0.5.4'
> packageVersion("readxl")
[1] '1.4.5'
> read_excel(
+   readxl_example("type-me.xlsx"),
+   sheet = "logical_coercion",
+   col_types = c("logical", "skip")
+ )

 *** caught segfault ***
address 0xffff11000000, cause 'invalid permissions'

Traceback:
 1: read_fun(path = path, sheet_i = sheet, limits = limits, shim = shim,     col_names = col_names, col_types = col_types, na = na, trim_ws = trim_ws,     guess_max = guess_max, progress = progress)
 2: tibble::as_tibble(l, .name_repair = .name_repair)
 3: set_readxl_names(read_fun(path = path, sheet_i = sheet, limits = limits,     shim = shim, col_names = col_names, col_types = col_types,     na = na, trim_ws = trim_ws, guess_max = guess_max, progress = progress),     .name_repair = .name_repair)
 4: read_excel_(path = path, sheet = sheet, range = range, col_names = col_names,     col_types = col_types, na = na, trim_ws = trim_ws, skip = skip,     n_max = n_max, guess_max = guess_max, progress = progress,     .name_repair = .name_repair, format = format)
 5: read_excel(readxl_example("type-me.xlsx"), sheet = "logical_coercion",     col_types = c("logical", "skip"))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions