Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/ops/collection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,12 @@ ray_t* ray_take_fn(ray_t* vec, ray_t* n_obj) {

return ray_error("type", "take: range take unsupported for %s", ray_type_name(vec->type));
}
/* Every scalar-count branch below turns the count into a magnitude with
* `n < 0 ? -n : n`; `-INT64_MIN` is signed-overflow UB and |INT64_MIN| is
* unallocatable anyway, so reject an INT64_MIN count (also the i64 null
* sentinel) once here, up front, for all of them. */
if (ray_is_atom(n_obj) && is_numeric(n_obj) && as_i64(n_obj) == INT64_MIN)
return ray_error("range", "take: count magnitude out of range");
/* Char take: (take 'a' n) → string of n copies of char */
if (ray_is_atom(vec) && vec->type == -RAY_STR && ray_str_len(vec) == 1 && ray_is_atom(n_obj) && is_numeric(n_obj)) {
int64_t n = as_i64(n_obj);
Expand Down Expand Up @@ -2015,7 +2021,10 @@ ray_t* ray_drop_fn(ray_t* vec, ray_t* n_obj) {
start = n < len ? n : len;
amount = len - start;
} else {
int64_t cut = -n;
/* `-INT64_MIN` is signed-overflow UB; a drop-from-end of that
* magnitude removes the whole collection (|n| >= len), so treat it as
* cut == len (amount 0) rather than negating. */
int64_t cut = (n == INT64_MIN) ? len : -n;
amount = cut < len ? len - cut : 0;
}
return collection_slice(vec, start, amount);
Expand Down
3 changes: 3 additions & 0 deletions test/rfl/collection/drop_cut_rotate_cross.rfl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
(drop [1 2 3 4 5] -2) -- [1 2 3]
(drop [1 2 3] 10) -- []
(drop [1 2 3] -10) -- []
;; INT64_MIN count: `-INT64_MIN` is signed-overflow UB (was tripped in
;; ray_drop_fn); |n| that large drops the whole collection.
(drop [1 2 3] -9223372036854775808) -- []
(drop "abcdef" 2) -- "cdef"
(drop "abcdef" -2) -- "abcd"
(drop ['a 'b 'c] 1) -- ['b 'c]
Expand Down
9 changes: 9 additions & 0 deletions test/rfl/collection/take.rfl
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,12 @@
(count (take [1 2 3 4 5] [2 0])) -- 0
;; range take with start = count → empty
(count (take [1 2 3 4 5] [5 3])) -- 0
;; INT64_MIN count: `-INT64_MIN` is signed-overflow UB (was tripped computing
;; the magnitude in every scalar-count take branch — vector, string, char,
;; scalar, list). Its magnitude is unrepresentable as int64, so it is a range
;; error, not UB followed by a bogus allocation.
(take [1 2 3] -9223372036854775808) !- range
(take "hello" -9223372036854775808) !- range
(take "a" -9223372036854775808) !- range
(take 42 -9223372036854775808) !- range
(take (list 1 2 3) -9223372036854775808) !- range
Loading