Skip to content

Commit 5dad336

Browse files
authored
Add a class to the vec_locate_matches() overflow error (#1869)
* Class the `vec_locate_matches()` overflow error * NEWS bullet
1 parent fc09bc3 commit 5dad336

File tree

8 files changed

+51
-13
lines changed

8 files changed

+51
-13
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# vctrs (development version)
22

3+
* Added a class to the `vec_locate_matches()` error that is thrown when an
4+
overflow would otherwise occur (#1845).
5+
36
* Fixed an issue with `vec_rank()` and 0-column data frames (#1863).
47

58
# vctrs 0.6.3

R/match.R

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,9 @@ compute_nesting_container_info <- function(x, condition) {
356356

357357
# ------------------------------------------------------------------------------
358358

359-
stop_matches <- function(class = NULL, ..., call = caller_env()) {
359+
stop_matches <- function(message = NULL, class = NULL, ..., call = caller_env()) {
360360
stop_vctrs(
361+
message = message,
361362
class = c(class, "vctrs_error_matches"),
362363
...,
363364
call = call
@@ -375,6 +376,27 @@ warn_matches <- function(message, class = NULL, ..., call = caller_env()) {
375376

376377
# ------------------------------------------------------------------------------
377378

379+
stop_matches_overflow <- function(size, call) {
380+
size <- format(size, scientific = FALSE)
381+
382+
# Pre-generating the message in this case because we want to use
383+
# `.internal = TRUE` and that doesn't work with lazy messages
384+
message <- c(
385+
"Match procedure results in an allocation larger than 2^31-1 elements.",
386+
i = glue::glue("Attempted allocation size was {size}.")
387+
)
388+
389+
stop_matches(
390+
message = message,
391+
class = "vctrs_error_matches_overflow",
392+
size = size,
393+
call = call,
394+
.internal = TRUE
395+
)
396+
}
397+
398+
# ------------------------------------------------------------------------------
399+
378400
stop_matches_nothing <- function(i, needles_arg, haystack_arg, call) {
379401
stop_matches(
380402
class = "vctrs_error_matches_nothing",

src/decl/match-decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ static inline
214214
r_ssize midpoint(r_ssize lhs, r_ssize rhs);
215215

216216
static inline
217-
void stop_matches_overflow(double size);
217+
void stop_matches_overflow(double size, struct r_lazy call);
218218

219219
static inline
220220
void stop_matches_nothing(r_ssize i,

src/match.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,7 @@ r_obj* expand_compact_indices(const int* v_o_haystack,
16371637

16381638
if (dbl_size_out > R_LEN_T_MAX) {
16391639
// TODO: Update this after a switch to long vector support
1640-
stop_matches_overflow(dbl_size_out);
1640+
stop_matches_overflow(dbl_size_out, error_call);
16411641
}
16421642

16431643
size_out = r_double_as_ssize(dbl_size_out);
@@ -2654,12 +2654,22 @@ r_ssize midpoint(r_ssize lhs, r_ssize rhs) {
26542654
// -----------------------------------------------------------------------------
26552655

26562656
static inline
2657-
void stop_matches_overflow(double size) {
2658-
r_stop_internal(
2659-
"Match procedure results in an allocation larger than 2^31-1 elements. "
2660-
"Attempted allocation size was %.0lf.",
2661-
size
2662-
);
2657+
void stop_matches_overflow(double size, struct r_lazy call) {
2658+
r_obj* syms[3] = {
2659+
syms_size,
2660+
syms_call,
2661+
NULL
2662+
};
2663+
r_obj* args[3] = {
2664+
KEEP(r_dbl(size)),
2665+
KEEP(r_lazy_eval_protect(call)),
2666+
NULL
2667+
};
2668+
2669+
r_obj* ffi_call = KEEP(r_call_n(syms_stop_matches_overflow, syms, args));
2670+
Rf_eval(ffi_call, vctrs_ns_env);
2671+
2672+
never_reached("stop_matches_overflow");
26632673
}
26642674

26652675
static inline

src/utils.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,7 @@ SEXP syms_s3_fallback = NULL;
15841584
SEXP syms_stop_incompatible_type = NULL;
15851585
SEXP syms_stop_incompatible_size = NULL;
15861586
SEXP syms_stop_assert_size = NULL;
1587+
SEXP syms_stop_matches_overflow = NULL;
15871588
SEXP syms_stop_matches_nothing = NULL;
15881589
SEXP syms_stop_matches_remaining = NULL;
15891590
SEXP syms_stop_matches_incomplete = NULL;
@@ -1865,6 +1866,7 @@ void vctrs_init_utils(SEXP ns) {
18651866
syms_stop_incompatible_type = Rf_install("stop_incompatible_type");
18661867
syms_stop_incompatible_size = Rf_install("stop_incompatible_size");
18671868
syms_stop_assert_size = Rf_install("stop_assert_size");
1869+
syms_stop_matches_overflow = Rf_install("stop_matches_overflow");
18681870
syms_stop_matches_nothing = Rf_install("stop_matches_nothing");
18691871
syms_stop_matches_remaining = Rf_install("stop_matches_remaining");
18701872
syms_stop_matches_incomplete = Rf_install("stop_matches_incomplete");

src/utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ extern SEXP syms_s3_fallback;
486486
extern SEXP syms_stop_incompatible_type;
487487
extern SEXP syms_stop_incompatible_size;
488488
extern SEXP syms_stop_assert_size;
489+
extern SEXP syms_stop_matches_overflow;
489490
extern SEXP syms_stop_matches_nothing;
490491
extern SEXP syms_stop_matches_remaining;
491492
extern SEXP syms_stop_matches_incomplete;

tests/testthat/_snaps/match.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,10 @@
670670
Code
671671
(expect_error(vec_locate_matches(1:1e+07, 1:1e+07, condition = ">=")))
672672
Output
673-
<error/rlang_error>
673+
<error/vctrs_error_matches_overflow>
674674
Error in `vec_locate_matches()`:
675-
! Match procedure results in an allocation larger than 2^31-1 elements. Attempted allocation size was 50000005000000.
676-
i In file 'match.c' at line <scrubbed>.
675+
! Match procedure results in an allocation larger than 2^31-1 elements.
676+
i Attempted allocation size was 50000005000000.
677677
i This is an internal error that was detected in the vctrs package.
678678
Please report it at <https://github.com/r-lib/vctrs/issues> with a reprex (<https://tidyverse.org/help/>) and the full backtrace.
679679

tests/testthat/test-match.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1791,7 +1791,7 @@ test_that("potential overflow on large output size is caught informatively", {
17911791
# intermediate `r_ssize` will be too large
17921792
skip_if(.Machine$sizeof.pointer < 8L, message = "No long vector support")
17931793

1794-
expect_snapshot(transform = scrub_internal_error_line_number, {
1794+
expect_snapshot({
17951795
(expect_error(vec_locate_matches(1:1e7, 1:1e7, condition = ">=")))
17961796
})
17971797
})

0 commit comments

Comments
 (0)