Skip to content

Commit de94601

Browse files
addaleaxjasnell
authored andcommitted
src: add Malloc() size param + overflow detection
Adds an optional second parameter to `node::Malloc()` and an optional third parameter to `node::Realloc()` giving the size/number of items to be allocated, in the style of `calloc(3)`. Use a proper overflow check using division; the previous `CHECK_GE(n * size, n);` would not detect all cases of overflow (e.g. `size == SIZE_MAX / 2 && n == 3`). PR-URL: #8482 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
1 parent f77cdf8 commit de94601

File tree

4 files changed

+25
-17
lines changed

4 files changed

+25
-17
lines changed

src/node_crypto.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5592,11 +5592,10 @@ void GetCurves(const FunctionCallbackInfo<Value>& args) {
55925592
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
55935593
Local<Array> arr = Array::New(env->isolate(), num_curves);
55945594
EC_builtin_curve* curves;
5595-
size_t alloc_size;
55965595

55975596
if (num_curves) {
5598-
alloc_size = sizeof(*curves) * num_curves;
5599-
curves = static_cast<EC_builtin_curve*>(node::Malloc(alloc_size));
5597+
curves = static_cast<EC_builtin_curve*>(node::Malloc(sizeof(*curves),
5598+
num_curves));
56005599

56015600
CHECK_NE(curves, nullptr);
56025601

src/string_bytes.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class ExternString: public ResourceType {
5454
return scope.Escape(String::Empty(isolate));
5555

5656
TypeName* new_data =
57-
static_cast<TypeName*>(node::Malloc(length * sizeof(*new_data)));
57+
static_cast<TypeName*>(node::Malloc(length, sizeof(*new_data)));
5858
if (new_data == nullptr) {
5959
return Local<String>();
6060
}

src/util-inl.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,31 +229,43 @@ bool StringEqualNoCaseN(const char* a, const char* b, size_t length) {
229229
return true;
230230
}
231231

232+
inline size_t MultiplyWithOverflowCheck(size_t a, size_t b) {
233+
size_t ret = a * b;
234+
if (a != 0)
235+
CHECK_EQ(b, ret / a);
236+
237+
return ret;
238+
}
239+
232240
// These should be used in our code as opposed to the native
233241
// versions as they abstract out some platform and or
234242
// compiler version specific functionality.
235243
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
236244
// that the standard allows them to either return a unique pointer or a
237245
// nullptr for zero-sized allocation requests. Normalize by always using
238246
// a nullptr.
239-
void* Realloc(void* pointer, size_t size) {
240-
if (size == 0) {
247+
void* Realloc(void* pointer, size_t n, size_t size) {
248+
size_t full_size = MultiplyWithOverflowCheck(size, n);
249+
250+
if (full_size == 0) {
241251
free(pointer);
242252
return nullptr;
243253
}
244-
return realloc(pointer, size);
254+
255+
return realloc(pointer, full_size);
245256
}
246257

247258
// As per spec realloc behaves like malloc if passed nullptr.
248-
void* Malloc(size_t size) {
259+
void* Malloc(size_t n, size_t size) {
260+
if (n == 0) n = 1;
249261
if (size == 0) size = 1;
250-
return Realloc(nullptr, size);
262+
return Realloc(nullptr, n, size);
251263
}
252264

253265
void* Calloc(size_t n, size_t size) {
254266
if (n == 0) n = 1;
255267
if (size == 0) size = 1;
256-
CHECK_GE(n * size, n); // Overflow guard.
268+
MultiplyWithOverflowCheck(size, n);
257269
return calloc(n, size);
258270
}
259271

src/util.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ namespace node {
3131
// that the standard allows them to either return a unique pointer or a
3232
// nullptr for zero-sized allocation requests. Normalize by always using
3333
// a nullptr.
34-
inline void* Realloc(void* pointer, size_t size);
35-
inline void* Malloc(size_t size);
36-
inline void* Calloc(size_t n, size_t size);
34+
inline void* Realloc(void* pointer, size_t n, size_t size = 1);
35+
inline void* Malloc(size_t n, size_t size = 1);
36+
inline void* Calloc(size_t n, size_t size = 1);
3737

3838
#ifdef __GNUC__
3939
#define NO_RETURN __attribute__((noreturn))
@@ -298,10 +298,7 @@ class MaybeStackBuffer {
298298
if (storage <= kStackStorageSize) {
299299
buf_ = buf_st_;
300300
} else {
301-
// Guard against overflow.
302-
CHECK_LE(storage, sizeof(T) * storage);
303-
304-
buf_ = static_cast<T*>(Malloc(sizeof(T) * storage));
301+
buf_ = static_cast<T*>(Malloc(sizeof(T), storage));
305302
CHECK_NE(buf_, nullptr);
306303
}
307304

0 commit comments

Comments
 (0)