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: https://github.com/nodejs/node/pull/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>
This commit is contained in:
parent
506cda6ea6
commit
eb927fac38
@ -5592,11 +5592,10 @@ void GetCurves(const FunctionCallbackInfo<Value>& args) {
|
|||||||
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
|
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
|
||||||
Local<Array> arr = Array::New(env->isolate(), num_curves);
|
Local<Array> arr = Array::New(env->isolate(), num_curves);
|
||||||
EC_builtin_curve* curves;
|
EC_builtin_curve* curves;
|
||||||
size_t alloc_size;
|
|
||||||
|
|
||||||
if (num_curves) {
|
if (num_curves) {
|
||||||
alloc_size = sizeof(*curves) * num_curves;
|
curves = static_cast<EC_builtin_curve*>(node::Malloc(sizeof(*curves),
|
||||||
curves = static_cast<EC_builtin_curve*>(node::Malloc(alloc_size));
|
num_curves));
|
||||||
|
|
||||||
CHECK_NE(curves, nullptr);
|
CHECK_NE(curves, nullptr);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class ExternString: public ResourceType {
|
|||||||
return scope.Escape(String::Empty(isolate));
|
return scope.Escape(String::Empty(isolate));
|
||||||
|
|
||||||
TypeName* new_data =
|
TypeName* new_data =
|
||||||
static_cast<TypeName*>(node::Malloc(length * sizeof(*new_data)));
|
static_cast<TypeName*>(node::Malloc(length, sizeof(*new_data)));
|
||||||
if (new_data == nullptr) {
|
if (new_data == nullptr) {
|
||||||
return Local<String>();
|
return Local<String>();
|
||||||
}
|
}
|
||||||
|
@ -229,6 +229,14 @@ bool StringEqualNoCaseN(const char* a, const char* b, size_t length) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline size_t MultiplyWithOverflowCheck(size_t a, size_t b) {
|
||||||
|
size_t ret = a * b;
|
||||||
|
if (a != 0)
|
||||||
|
CHECK_EQ(b, ret / a);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// These should be used in our code as opposed to the native
|
// These should be used in our code as opposed to the native
|
||||||
// versions as they abstract out some platform and or
|
// versions as they abstract out some platform and or
|
||||||
// compiler version specific functionality.
|
// compiler version specific functionality.
|
||||||
@ -236,24 +244,28 @@ bool StringEqualNoCaseN(const char* a, const char* b, size_t length) {
|
|||||||
// that the standard allows them to either return a unique pointer or a
|
// that the standard allows them to either return a unique pointer or a
|
||||||
// nullptr for zero-sized allocation requests. Normalize by always using
|
// nullptr for zero-sized allocation requests. Normalize by always using
|
||||||
// a nullptr.
|
// a nullptr.
|
||||||
void* Realloc(void* pointer, size_t size) {
|
void* Realloc(void* pointer, size_t n, size_t size) {
|
||||||
if (size == 0) {
|
size_t full_size = MultiplyWithOverflowCheck(size, n);
|
||||||
|
|
||||||
|
if (full_size == 0) {
|
||||||
free(pointer);
|
free(pointer);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return realloc(pointer, size);
|
|
||||||
|
return realloc(pointer, full_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// As per spec realloc behaves like malloc if passed nullptr.
|
// As per spec realloc behaves like malloc if passed nullptr.
|
||||||
void* Malloc(size_t size) {
|
void* Malloc(size_t n, size_t size) {
|
||||||
|
if (n == 0) n = 1;
|
||||||
if (size == 0) size = 1;
|
if (size == 0) size = 1;
|
||||||
return Realloc(nullptr, size);
|
return Realloc(nullptr, n, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Calloc(size_t n, size_t size) {
|
void* Calloc(size_t n, size_t size) {
|
||||||
if (n == 0) n = 1;
|
if (n == 0) n = 1;
|
||||||
if (size == 0) size = 1;
|
if (size == 0) size = 1;
|
||||||
CHECK_GE(n * size, n); // Overflow guard.
|
MultiplyWithOverflowCheck(size, n);
|
||||||
return calloc(n, size);
|
return calloc(n, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
src/util.h
11
src/util.h
@ -22,9 +22,9 @@ namespace node {
|
|||||||
// that the standard allows them to either return a unique pointer or a
|
// that the standard allows them to either return a unique pointer or a
|
||||||
// nullptr for zero-sized allocation requests. Normalize by always using
|
// nullptr for zero-sized allocation requests. Normalize by always using
|
||||||
// a nullptr.
|
// a nullptr.
|
||||||
inline void* Realloc(void* pointer, size_t size);
|
inline void* Realloc(void* pointer, size_t n, size_t size = 1);
|
||||||
inline void* Malloc(size_t size);
|
inline void* Malloc(size_t n, size_t size = 1);
|
||||||
inline void* Calloc(size_t n, size_t size);
|
inline void* Calloc(size_t n, size_t size = 1);
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define NO_RETURN __attribute__((noreturn))
|
#define NO_RETURN __attribute__((noreturn))
|
||||||
@ -285,10 +285,7 @@ class MaybeStackBuffer {
|
|||||||
if (storage <= kStackStorageSize) {
|
if (storage <= kStackStorageSize) {
|
||||||
buf_ = buf_st_;
|
buf_ = buf_st_;
|
||||||
} else {
|
} else {
|
||||||
// Guard against overflow.
|
buf_ = static_cast<T*>(Malloc(sizeof(T), storage));
|
||||||
CHECK_LE(storage, sizeof(T) * storage);
|
|
||||||
|
|
||||||
buf_ = static_cast<T*>(Malloc(sizeof(T) * storage));
|
|
||||||
CHECK_NE(buf_, nullptr);
|
CHECK_NE(buf_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user