Skip to content

Commit 311c12b

Browse files
authored
Use safer r_memcpy() and r_memset() everywhere (#1797)
* Introduce `r_memcpy()` and `r_memset()` * Use `r_memcpy()` and `r_memset()` * NEWS bullet
1 parent 5009b3d commit 311c12b

File tree

13 files changed

+52
-18
lines changed

13 files changed

+52
-18
lines changed

NEWS.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# rlang (development version)
22

3+
* C code no longer calls `memcpy()` and `memset()` on 0-length R object memory
4+
(#1797).
5+
6+
37
# rlang 1.1.6
48

59
* Fixes for CRAN checks.

src/internal/cnd.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const char* rlang_format_error_arg(r_obj* arg) {
4141

4242
// Uses the vmax protection stack.
4343
char* out = R_alloc(n, sizeof(char));
44-
memcpy(out, arg_str, n);
44+
r_memcpy(out, arg_str, n);
4545

4646
FREE(1);
4747
return out;
@@ -216,7 +216,7 @@ const char* rlang_obj_type_friendly_full(r_obj* x, bool value, bool _length) {
216216
// Uses the vmax protection stack.
217217
int n = strlen(out_str) + 1;
218218
char* out = R_alloc(n, sizeof(char));
219-
memcpy(out, out_str, n);
219+
r_memcpy(out, out_str, n);
220220

221221
FREE(1);
222222
return out;

src/internal/hash.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ void hash_skip(struct hash_state_t* p_state, void* p_input, int n) {
225225
if (p_state->n_skipped == N_BYTES_SERIALIZATION_INFO) {
226226
// We've skipped all serialization info bytes.
227227
// Incoming bytes tell the size of the native encoding string.
228-
memcpy(&p_state->n_native_enc, p_input, sizeof(int));
228+
r_memcpy(&p_state->n_native_enc, p_input, sizeof(int));
229229
p_state->n_skipped += n;
230230
return;
231231
}

src/internal/names.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ r_obj* names_as_unique(r_obj* names, bool quiet) {
6565
char buf[buf_size];
6666
buf[0] = '\0';
6767

68-
memcpy(buf, name, size);
68+
r_memcpy(buf, name, size);
6969
int remaining = buf_size - size;
7070

7171
int needed = snprintf(buf + size,

src/internal/sym-unescape.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ r_obj* str_unserialise_unicode(r_obj* r_string) {
8686
// Need to check first if the string has any UTF-8 escapes.
8787
int orig_len = strlen(re_enc);
8888
char tmp[orig_len + 1];
89-
memcpy(tmp, re_enc, orig_len + 1);
89+
r_memcpy(tmp, re_enc, orig_len + 1);
9090
return unescape_char_to_sexp(tmp);
9191
} else {
9292
// The string has been copied so it's safe to use as buffer

src/internal/vec-raw.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ r_obj* ffi_raw_deparse_str(r_obj* x, r_obj* prefix, r_obj* suffix) {
3333
r_obj* buf = KEEP(r_alloc_raw(len));
3434
char* p_buf = (char*) r_raw_begin(buf);
3535

36-
memcpy(p_buf, s_prefix, len_prefix);
36+
r_memcpy(p_buf, s_prefix, len_prefix);
3737
p_buf += len_prefix;
3838

3939
const char* lookup = "0123456789abcdef";
@@ -44,7 +44,7 @@ r_obj* ffi_raw_deparse_str(r_obj* x, r_obj* prefix, r_obj* suffix) {
4444
*p_buf++ = lookup[value % 16];
4545
}
4646

47-
memcpy(p_buf, s_suffix, len_suffix);
47+
r_memcpy(p_buf, s_suffix, len_suffix);
4848
p_buf += len_suffix;
4949

5050
// Invariant: p_buf == r_raw_begin(buf) + len

src/rlang/c-utils.h

+29
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <inttypes.h>
99
#include <math.h>
1010
#include <float.h>
11+
#include <string.h>
1112
#include "cnd.h"
1213

1314
#define R_ARR_SIZEOF(X) sizeof(X) / sizeof(X[0])
@@ -164,4 +165,32 @@ double r_double_mult(double x, double y) {
164165
return out;
165166
}
166167

168+
// Slightly safer version of `memcpy()` for use with R object memory
169+
//
170+
// Prefer this over `memcpy()`, especially when providing pointers to R object
171+
// memory. As of R 4.5.0, `DATAPTR()` and friends return `(void*) 1` on 0-length
172+
// R objects, so we must be extremely careful to never use dereference those
173+
// pointers. In particular, it is not safe to call `memcpy(dest, src, 0)` on
174+
// some machines (likely with sanitizers active) when either `dest` or `src`
175+
// resolve to `(void*) 1`.
176+
//
177+
// https://github.com/r-lib/vctrs/pull/1968
178+
// https://github.com/r-devel/r-svn/blob/9976c3d7f08c754593d01ba8380afb6be803dde2/src/main/memory.c#L4137-L4150
179+
static inline
180+
void r_memcpy(void* dest, const void* src, size_t count) {
181+
if (count) {
182+
memcpy(dest, src, count);
183+
}
184+
}
185+
186+
// Slightly safer version of `memset()` for use with R object memory
187+
//
188+
// See `r_memcpy()` for rationale
189+
static inline
190+
void r_memset(void* dest, int value, size_t count) {
191+
if (count) {
192+
memset(dest, value, count);
193+
}
194+
}
195+
167196
#endif

src/rlang/dict.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void r_dict_resize(struct r_dict* p_dict, r_ssize size) {
8585
r_obj* old_shelter = p_dict->shelter;
8686
r_list_poke(old_shelter, 1, r_list_get(p_new_dict->shelter, 1));
8787

88-
memcpy(p_dict, p_new_dict, sizeof(*p_dict));
88+
r_memcpy(p_dict, p_new_dict, sizeof(*p_dict));
8989
p_dict->shelter = old_shelter;
9090

9191
FREE(1);

src/rlang/dyn-array.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ void r_dyn_push_back(struct r_dyn_array* p_arr,
7676
r_obj* value = *((r_obj* const *) p_elt);
7777
p_arr->barrier_set(p_arr->data, loc, value);
7878
} else if (p_elt) {
79-
memcpy(r_dyn_last(p_arr), p_elt, p_arr->elt_byte_size);
79+
r_memcpy(r_dyn_last(p_arr), p_elt, p_arr->elt_byte_size);
8080
} else {
81-
memset(r_dyn_last(p_arr), 0, p_arr->elt_byte_size);
81+
r_memset(r_dyn_last(p_arr), 0, p_arr->elt_byte_size);
8282
}
8383
}
8484

src/rlang/dyn-list-of.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ bool reserve_push_back(struct r_dyn_list_of* p_lof, r_ssize i, void* p_elt) {
208208
void* p = ((unsigned char*) p_lof->v_reserve) + offset;
209209

210210
if (p_elt) {
211-
memcpy(p, p_elt, p_lof->elt_byte_size);
211+
r_memcpy(p, p_elt, p_lof->elt_byte_size);
212212
} else {
213-
memset(p, 0, p_lof->elt_byte_size);
213+
r_memset(p, 0, p_lof->elt_byte_size);
214214
}
215215

216216
return true;
@@ -227,7 +227,7 @@ void reserve_move(struct r_dyn_list_of* p_lof, r_ssize i, void* p_elt) {
227227

228228
void* v_new = r_dyn_begin(p_new);
229229
void* v_old = R_DYN_GET(struct r_pair_ptr_ssize, p_lof->p_arrays, i).ptr;
230-
memcpy(v_new, v_old, r_ssize_mult(n, p_lof->elt_byte_size));
230+
r_memcpy(v_new, v_old, r_ssize_mult(n, p_lof->elt_byte_size));
231231

232232
p_new->count = n;
233233

src/rlang/env-binding.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static r_obj* new_binding_types(r_ssize n) {
1414
r_obj* types = r_alloc_integer(n);
1515

1616
int* types_ptr = r_int_begin(types);
17-
memset(types_ptr, 0, n * sizeof *types_ptr);
17+
r_memset(types_ptr, 0, n * sizeof *types_ptr);
1818

1919
return types;
2020
}

src/rlang/vec.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ r_obj* r_chr_n(const char* const * strings, r_ssize n) {
3838
C_TYPE* p_out = DEREF(out); \
3939
\
4040
r_ssize cpy_size = (size > x_size) ? x_size : size; \
41-
memcpy(p_out, p_x, cpy_size * sizeof(C_TYPE)); \
41+
r_memcpy(p_out, p_x, cpy_size * sizeof(C_TYPE)); \
4242
\
4343
FREE(1); \
4444
return out; \

src/rlang/vec.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <string.h>
77
#include "rlang-types.h"
8+
#include "c-utils.h"
89
#include "cnd.h"
910
#include "globals.h"
1011
#include "obj.h"
@@ -219,7 +220,7 @@ r_obj* r_alloc_raw0(r_ssize n) {
219220
r_obj* out = r_alloc_raw(n);
220221

221222
unsigned char* p_out = (unsigned char*) r_raw_begin(out);
222-
memset(p_out, 0, n);
223+
r_memset(p_out, 0, n);
223224

224225
return out;
225226
}
@@ -438,7 +439,7 @@ r_obj* r_vec_n(enum r_type type, void* v_src, r_ssize n) {
438439
case R_TYPE_complex:
439440
case R_TYPE_raw: {
440441
r_obj* out = r_alloc_vector(type, n);
441-
memcpy(r_vec_begin(out), v_src, n * r_vec_elt_sizeof0(type));
442+
r_memcpy(r_vec_begin(out), v_src, n * r_vec_elt_sizeof0(type));
442443
return out;
443444
}
444445
case R_TYPE_character:
@@ -474,7 +475,7 @@ r_obj* r_raw_n(int* v_src, r_ssize n) {
474475
static inline
475476
r_obj* r_copy_in_raw(const void* src, size_t size) {
476477
r_obj* out = r_alloc_raw(size);
477-
memcpy(r_raw_begin(out), src, size);
478+
r_memcpy(r_raw_begin(out), src, size);
478479
return out;
479480
}
480481

0 commit comments

Comments
 (0)