Skip to content

Commit 51e09d0

Browse files
mhdawsonMyles Borins
authored and
Myles Borins
committed
src: normalize malloc, realloc
malloc(0) and realloc(ptr, 0) have implementation-defined behavior in that the standard allows them to either return a unique pointer or a nullptr for zero-sized allocation requests. Normalize by always using a nullptr. - Introduce node::malloc, node::realloc and node::calloc that should be used throught our source. - Update all existing node source files to use the new functions instead of the native allocation functions. Fixes: #7549 PR-URL: #7564 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 3b5cede commit 51e09d0

11 files changed

+67
-32
lines changed

src/cares_wrap.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ static void ares_poll_close_cb(uv_handle_t* watcher) {
175175

176176
/* Allocates and returns a new node_ares_task */
177177
static node_ares_task* ares_task_create(Environment* env, ares_socket_t sock) {
178-
node_ares_task* task = static_cast<node_ares_task*>(malloc(sizeof(*task)));
178+
node_ares_task* task =
179+
static_cast<node_ares_task*>(node::Malloc(sizeof(*task)));
179180

180181
if (task == nullptr) {
181182
/* Out of memory. */

src/node.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -978,9 +978,9 @@ void* ArrayBufferAllocator::Allocate(size_t size) {
978978
if (env_ == nullptr ||
979979
!env_->array_buffer_allocator_info()->no_zero_fill() ||
980980
zero_fill_all_buffers)
981-
return calloc(size, 1);
981+
return node::Calloc(size, 1);
982982
env_->array_buffer_allocator_info()->reset_fill_flag();
983-
return malloc(size);
983+
return node::Malloc(size);
984984
}
985985

986986
static bool DomainHasErrorHandler(const Environment* env,

src/node_buffer.cc

+4-8
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
size_t length = end - start;
5050

5151
#define BUFFER_MALLOC(length) \
52-
zero_fill_all_buffers ? calloc(length, 1) : malloc(length)
52+
zero_fill_all_buffers ? node::Calloc(length, 1) : node::Malloc(length)
5353

5454
namespace node {
5555

@@ -247,10 +247,6 @@ MaybeLocal<Object> New(Isolate* isolate,
247247
size_t actual = 0;
248248
char* data = nullptr;
249249

250-
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
251-
// that the standard allows them to either return a unique pointer or a
252-
// nullptr for zero-sized allocation requests. Normalize by always using
253-
// a nullptr.
254250
if (length > 0) {
255251
data = static_cast<char*>(BUFFER_MALLOC(length));
256252

@@ -264,7 +260,7 @@ MaybeLocal<Object> New(Isolate* isolate,
264260
free(data);
265261
data = nullptr;
266262
} else if (actual < length) {
267-
data = static_cast<char*>(realloc(data, actual));
263+
data = static_cast<char*>(node::Realloc(data, actual));
268264
CHECK_NE(data, nullptr);
269265
}
270266
}
@@ -343,7 +339,7 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
343339
void* new_data;
344340
if (length > 0) {
345341
CHECK_NE(data, nullptr);
346-
new_data = malloc(length);
342+
new_data = node::Malloc(length);
347343
if (new_data == nullptr)
348344
return Local<Object>();
349345
memcpy(new_data, data, length);
@@ -931,7 +927,7 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
931927
needle_length,
932928
offset);
933929
} else if (enc == BINARY) {
934-
uint8_t* needle_data = static_cast<uint8_t*>(malloc(needle_length));
930+
uint8_t* needle_data = static_cast<uint8_t*>(node::Malloc(needle_length));
935931
if (needle_data == nullptr) {
936932
return args.GetReturnValue().Set(-1);
937933
}

src/node_crypto.cc

+10-10
Original file line numberDiff line numberDiff line change
@@ -2090,7 +2090,7 @@ int SSLWrap<Base>::TLSExtStatusCallback(SSL* s, void* arg) {
20902090
size_t len = Buffer::Length(obj);
20912091

20922092
// OpenSSL takes control of the pointer after accepting it
2093-
char* data = reinterpret_cast<char*>(malloc(len));
2093+
char* data = reinterpret_cast<char*>(node::Malloc(len));
20942094
CHECK_NE(data, nullptr);
20952095
memcpy(data, resp, len);
20962096

@@ -3139,7 +3139,7 @@ bool CipherBase::GetAuthTag(char** out, unsigned int* out_len) const {
31393139
if (initialised_ || kind_ != kCipher || !auth_tag_)
31403140
return false;
31413141
*out_len = auth_tag_len_;
3142-
*out = static_cast<char*>(malloc(auth_tag_len_));
3142+
*out = static_cast<char*>(node::Malloc(auth_tag_len_));
31433143
CHECK_NE(*out, nullptr);
31443144
memcpy(*out, auth_tag_, auth_tag_len_);
31453145
return true;
@@ -4694,7 +4694,7 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
46944694
// NOTE: field_size is in bits
46954695
int field_size = EC_GROUP_get_degree(ecdh->group_);
46964696
size_t out_len = (field_size + 7) / 8;
4697-
char* out = static_cast<char*>(malloc(out_len));
4697+
char* out = static_cast<char*>(node::Malloc(out_len));
46984698
CHECK_NE(out, nullptr);
46994699

47004700
int r = ECDH_compute_key(out, out_len, pub, ecdh->key_, nullptr);
@@ -4733,7 +4733,7 @@ void ECDH::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
47334733
if (size == 0)
47344734
return env->ThrowError("Failed to get public key length");
47354735

4736-
unsigned char* out = static_cast<unsigned char*>(malloc(size));
4736+
unsigned char* out = static_cast<unsigned char*>(node::Malloc(size));
47374737
CHECK_NE(out, nullptr);
47384738

47394739
int r = EC_POINT_point2oct(ecdh->group_, pub, form, out, size, nullptr);
@@ -4762,7 +4762,7 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
47624762
return env->ThrowError("Failed to get ECDH private key");
47634763

47644764
int size = BN_num_bytes(b);
4765-
unsigned char* out = static_cast<unsigned char*>(malloc(size));
4765+
unsigned char* out = static_cast<unsigned char*>(node::Malloc(size));
47664766
CHECK_NE(out, nullptr);
47674767

47684768
if (size != BN_bn2bin(b, out)) {
@@ -4839,7 +4839,7 @@ class PBKDF2Request : public AsyncWrap {
48394839
saltlen_(saltlen),
48404840
salt_(salt),
48414841
keylen_(keylen),
4842-
key_(static_cast<char*>(malloc(keylen))),
4842+
key_(static_cast<char*>(node::Malloc(keylen))),
48434843
iter_(iter) {
48444844
if (key() == nullptr)
48454845
FatalError("node::PBKDF2Request()", "Out of Memory");
@@ -5002,7 +5002,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
50025002

50035003
THROW_AND_RETURN_IF_NOT_BUFFER(args[1]);
50045004

5005-
pass = static_cast<char*>(malloc(passlen));
5005+
pass = static_cast<char*>(node::Malloc(passlen));
50065006
if (pass == nullptr) {
50075007
FatalError("node::PBKDF2()", "Out of Memory");
50085008
}
@@ -5014,7 +5014,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
50145014
goto err;
50155015
}
50165016

5017-
salt = static_cast<char*>(malloc(saltlen));
5017+
salt = static_cast<char*>(node::Malloc(saltlen));
50185018
if (salt == nullptr) {
50195019
FatalError("node::PBKDF2()", "Out of Memory");
50205020
}
@@ -5107,7 +5107,7 @@ class RandomBytesRequest : public AsyncWrap {
51075107
: AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO),
51085108
error_(0),
51095109
size_(size),
5110-
data_(static_cast<char*>(malloc(size))) {
5110+
data_(static_cast<char*>(node::Malloc(size))) {
51115111
if (data() == nullptr)
51125112
FatalError("node::RandomBytesRequest()", "Out of Memory");
51135113
Wrap(object, this);
@@ -5336,7 +5336,7 @@ void GetCurves(const FunctionCallbackInfo<Value>& args) {
53365336

53375337
if (num_curves) {
53385338
alloc_size = sizeof(*curves) * num_curves;
5339-
curves = static_cast<EC_builtin_curve*>(malloc(alloc_size));
5339+
curves = static_cast<EC_builtin_curve*>(node::Malloc(alloc_size));
53405340

53415341
CHECK_NE(curves, nullptr);
53425342

src/node_internals.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
216216
inline void set_env(Environment* env) { env_ = env; }
217217

218218
virtual void* Allocate(size_t size); // Defined in src/node.cc
219-
virtual void* AllocateUninitialized(size_t size) { return malloc(size); }
219+
virtual void* AllocateUninitialized(size_t size)
220+
{ return node::Malloc(size); }
220221
virtual void Free(void* data, size_t) { free(data); }
221222

222223
private:

src/stream_wrap.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void StreamWrap::OnAlloc(uv_handle_t* handle,
154154

155155

156156
void StreamWrap::OnAllocImpl(size_t size, uv_buf_t* buf, void* ctx) {
157-
buf->base = static_cast<char*>(malloc(size));
157+
buf->base = static_cast<char*>(node::Malloc(size));
158158
buf->len = size;
159159

160160
if (buf->base == nullptr && size > 0) {
@@ -210,7 +210,7 @@ void StreamWrap::OnReadImpl(ssize_t nread,
210210
return;
211211
}
212212

213-
char* base = static_cast<char*>(realloc(buf->base, nread));
213+
char* base = static_cast<char*>(node::Realloc(buf->base, nread));
214214
CHECK_LE(static_cast<size_t>(nread), buf->len);
215215

216216
if (pending == UV_TCP) {

src/string_bytes.cc

+4-4
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*>(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
}
@@ -784,7 +784,7 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
784784

785785
case ASCII:
786786
if (contains_non_ascii(buf, buflen)) {
787-
char* out = static_cast<char*>(malloc(buflen));
787+
char* out = static_cast<char*>(node::Malloc(buflen));
788788
if (out == nullptr) {
789789
return Local<String>();
790790
}
@@ -819,7 +819,7 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
819819

820820
case BASE64: {
821821
size_t dlen = base64_encoded_size(buflen);
822-
char* dst = static_cast<char*>(malloc(dlen));
822+
char* dst = static_cast<char*>(node::Malloc(dlen));
823823
if (dst == nullptr) {
824824
return Local<String>();
825825
}
@@ -838,7 +838,7 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
838838

839839
case HEX: {
840840
size_t dlen = buflen * 2;
841-
char* dst = static_cast<char*>(malloc(dlen));
841+
char* dst = static_cast<char*>(node::Malloc(dlen));
842842
if (dst == nullptr) {
843843
return Local<String>();
844844
}

src/tls_wrap.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ void TLSWrap::OnReadImpl(ssize_t nread,
662662

663663

664664
void TLSWrap::OnAllocSelf(size_t suggested_size, uv_buf_t* buf, void* ctx) {
665-
buf->base = static_cast<char*>(malloc(suggested_size));
665+
buf->base = static_cast<char*>(node::Malloc(suggested_size));
666666
CHECK_NE(buf->base, nullptr);
667667
buf->len = suggested_size;
668668
}

src/udp_wrap.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
358358
void UDPWrap::OnAlloc(uv_handle_t* handle,
359359
size_t suggested_size,
360360
uv_buf_t* buf) {
361-
buf->base = static_cast<char*>(malloc(suggested_size));
361+
buf->base = static_cast<char*>(node::Malloc(suggested_size));
362362
buf->len = suggested_size;
363363

364364
if (buf->base == nullptr && suggested_size > 0) {
@@ -400,7 +400,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
400400
return;
401401
}
402402

403-
char* base = static_cast<char*>(realloc(buf->base, nread));
403+
char* base = static_cast<char*>(node::Realloc(buf->base, nread));
404404
argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
405405
argv[3] = AddressToJS(env, addr);
406406
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);

src/util-inl.h

+26
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,32 @@ bool StringEqualNoCase(const char* a, const char* b) {
217217
return false;
218218
}
219219

220+
// These should be used in our code as opposed to the native
221+
// versions as they abstract out some platform and or
222+
// compiler version specific functionality.
223+
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
224+
// that the standard allows them to either return a unique pointer or a
225+
// nullptr for zero-sized allocation requests. Normalize by always using
226+
// a nullptr.
227+
void* Realloc(void* pointer, size_t size) {
228+
if (size == 0) {
229+
free(pointer);
230+
return nullptr;
231+
}
232+
return realloc(pointer, size);
233+
}
234+
235+
// As per spec realloc behaves like malloc if passed nullptr.
236+
void* Malloc(size_t size) {
237+
return Realloc(nullptr, size);
238+
}
239+
240+
void* Calloc(size_t n, size_t size) {
241+
if ((n == 0) || (size == 0)) return nullptr;
242+
CHECK_GE(n * size, n); // Overflow guard.
243+
return calloc(n, size);
244+
}
245+
220246
} // namespace node
221247

222248
#endif // SRC_UTIL_INL_H_

src/util.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@
1616

1717
namespace node {
1818

19+
// These should be used in our code as opposed to the native
20+
// versions as they abstract out some platform and or
21+
// compiler version specific functionality
22+
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
23+
// that the standard allows them to either return a unique pointer or a
24+
// nullptr for zero-sized allocation requests. Normalize by always using
25+
// a nullptr.
26+
inline void* Realloc(void* pointer, size_t size);
27+
inline void* Malloc(size_t size);
28+
inline void* Calloc(size_t n, size_t size);
29+
1930
#ifdef __APPLE__
2031
template <typename T> using remove_reference = std::tr1::remove_reference<T>;
2132
#else
@@ -250,7 +261,7 @@ class MaybeStackBuffer {
250261
// Guard against overflow.
251262
CHECK_LE(storage, sizeof(T) * storage);
252263

253-
buf_ = static_cast<T*>(malloc(sizeof(T) * storage));
264+
buf_ = static_cast<T*>(Malloc(sizeof(T) * storage));
254265
CHECK_NE(buf_, nullptr);
255266
}
256267

0 commit comments

Comments
 (0)