Skip to content

Commit a00ccb0

Browse files
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 a290ddf commit a00ccb0

11 files changed

+67
-32
lines changed

src/cares_wrap.cc

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

143143
/* Allocates and returns a new node_ares_task */
144144
static node_ares_task* ares_task_create(Environment* env, ares_socket_t sock) {
145-
node_ares_task* task = static_cast<node_ares_task*>(malloc(sizeof(*task)));
145+
node_ares_task* task =
146+
static_cast<node_ares_task*>(node::Malloc(sizeof(*task)));
146147

147148
if (task == nullptr) {
148149
/* Out of memory. */

src/node.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -979,9 +979,9 @@ Local<Value> WinapiErrnoException(Isolate* isolate,
979979

980980
void* ArrayBufferAllocator::Allocate(size_t size) {
981981
if (zero_fill_field_ || zero_fill_all_buffers)
982-
return calloc(size, 1);
982+
return node::Calloc(size, 1);
983983
else
984-
return malloc(size);
984+
return node::Malloc(size);
985985
}
986986

987987
static bool DomainHasErrorHandler(const Environment* env,

src/node_buffer.cc

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

5252
#define BUFFER_MALLOC(length) \
53-
zero_fill_all_buffers ? calloc(length, 1) : malloc(length)
53+
zero_fill_all_buffers ? node::Calloc(length, 1) : node::Malloc(length)
5454

5555
#if defined(__GNUC__) || defined(__clang__)
5656
#define BSWAP_INTRINSIC_2(x) __builtin_bswap16(x)
@@ -265,10 +265,6 @@ MaybeLocal<Object> New(Isolate* isolate,
265265
size_t actual = 0;
266266
char* data = nullptr;
267267

268-
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
269-
// that the standard allows them to either return a unique pointer or a
270-
// nullptr for zero-sized allocation requests. Normalize by always using
271-
// a nullptr.
272268
if (length > 0) {
273269
data = static_cast<char*>(BUFFER_MALLOC(length));
274270

@@ -282,7 +278,7 @@ MaybeLocal<Object> New(Isolate* isolate,
282278
free(data);
283279
data = nullptr;
284280
} else if (actual < length) {
285-
data = static_cast<char*>(realloc(data, actual));
281+
data = static_cast<char*>(node::Realloc(data, actual));
286282
CHECK_NE(data, nullptr);
287283
}
288284
}
@@ -361,7 +357,7 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
361357
void* new_data;
362358
if (length > 0) {
363359
CHECK_NE(data, nullptr);
364-
new_data = malloc(length);
360+
new_data = node::Malloc(length);
365361
if (new_data == nullptr)
366362
return Local<Object>();
367363
memcpy(new_data, data, length);
@@ -1083,7 +1079,7 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
10831079
offset,
10841080
is_forward);
10851081
} else if (enc == LATIN1) {
1086-
uint8_t* needle_data = static_cast<uint8_t*>(malloc(needle_length));
1082+
uint8_t* needle_data = static_cast<uint8_t*>(node::Malloc(needle_length));
10871083
if (needle_data == nullptr) {
10881084
return args.GetReturnValue().Set(-1);
10891085
}

src/node_crypto.cc

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

22812281
// OpenSSL takes control of the pointer after accepting it
2282-
char* data = reinterpret_cast<char*>(malloc(len));
2282+
char* data = reinterpret_cast<char*>(node::Malloc(len));
22832283
CHECK_NE(data, nullptr);
22842284
memcpy(data, resp, len);
22852285

@@ -3330,7 +3330,7 @@ bool CipherBase::GetAuthTag(char** out, unsigned int* out_len) const {
33303330
if (initialised_ || kind_ != kCipher || !auth_tag_)
33313331
return false;
33323332
*out_len = auth_tag_len_;
3333-
*out = static_cast<char*>(malloc(auth_tag_len_));
3333+
*out = static_cast<char*>(node::Malloc(auth_tag_len_));
33343334
CHECK_NE(*out, nullptr);
33353335
memcpy(*out, auth_tag_, auth_tag_len_);
33363336
return true;
@@ -4906,7 +4906,7 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
49064906
// NOTE: field_size is in bits
49074907
int field_size = EC_GROUP_get_degree(ecdh->group_);
49084908
size_t out_len = (field_size + 7) / 8;
4909-
char* out = static_cast<char*>(malloc(out_len));
4909+
char* out = static_cast<char*>(node::Malloc(out_len));
49104910
CHECK_NE(out, nullptr);
49114911

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

4945-
unsigned char* out = static_cast<unsigned char*>(malloc(size));
4945+
unsigned char* out = static_cast<unsigned char*>(node::Malloc(size));
49464946
CHECK_NE(out, nullptr);
49474947

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

49704970
int size = BN_num_bytes(b);
4971-
unsigned char* out = static_cast<unsigned char*>(malloc(size));
4971+
unsigned char* out = static_cast<unsigned char*>(node::Malloc(size));
49724972
CHECK_NE(out, nullptr);
49734973

49744974
if (size != BN_bn2bin(b, out)) {
@@ -5099,7 +5099,7 @@ class PBKDF2Request : public AsyncWrap {
50995099
saltlen_(saltlen),
51005100
salt_(salt),
51015101
keylen_(keylen),
5102-
key_(static_cast<char*>(malloc(keylen))),
5102+
key_(static_cast<char*>(node::Malloc(keylen))),
51035103
iter_(iter) {
51045104
if (key() == nullptr)
51055105
FatalError("node::PBKDF2Request()", "Out of Memory");
@@ -5262,7 +5262,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
52625262

52635263
THROW_AND_RETURN_IF_NOT_BUFFER(args[1], "Salt");
52645264

5265-
pass = static_cast<char*>(malloc(passlen));
5265+
pass = static_cast<char*>(node::Malloc(passlen));
52665266
if (pass == nullptr) {
52675267
FatalError("node::PBKDF2()", "Out of Memory");
52685268
}
@@ -5274,7 +5274,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
52745274
goto err;
52755275
}
52765276

5277-
salt = static_cast<char*>(malloc(saltlen));
5277+
salt = static_cast<char*>(node::Malloc(saltlen));
52785278
if (salt == nullptr) {
52795279
FatalError("node::PBKDF2()", "Out of Memory");
52805280
}
@@ -5367,7 +5367,7 @@ class RandomBytesRequest : public AsyncWrap {
53675367
: AsyncWrap(env, object, AsyncWrap::PROVIDER_CRYPTO),
53685368
error_(0),
53695369
size_(size),
5370-
data_(static_cast<char*>(malloc(size))) {
5370+
data_(static_cast<char*>(node::Malloc(size))) {
53715371
if (data() == nullptr)
53725372
FatalError("node::RandomBytesRequest()", "Out of Memory");
53735373
Wrap(object, this);
@@ -5596,7 +5596,7 @@ void GetCurves(const FunctionCallbackInfo<Value>& args) {
55965596

55975597
if (num_curves) {
55985598
alloc_size = sizeof(*curves) * num_curves;
5599-
curves = static_cast<EC_builtin_curve*>(malloc(alloc_size));
5599+
curves = static_cast<EC_builtin_curve*>(node::Malloc(alloc_size));
56005600

56015601
CHECK_NE(curves, nullptr);
56025602

src/node_internals.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
180180
inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
181181

182182
virtual void* Allocate(size_t size); // Defined in src/node.cc
183-
virtual void* AllocateUninitialized(size_t size) { return malloc(size); }
183+
virtual void* AllocateUninitialized(size_t size)
184+
{ return node::Malloc(size); }
184185
virtual void Free(void* data, size_t) { free(data); }
185186

186187
private:

src/stream_wrap.cc

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

149149

150150
void StreamWrap::OnAllocImpl(size_t size, uv_buf_t* buf, void* ctx) {
151-
buf->base = static_cast<char*>(malloc(size));
151+
buf->base = static_cast<char*>(node::Malloc(size));
152152
buf->len = size;
153153

154154
if (buf->base == nullptr && size > 0) {
@@ -204,7 +204,7 @@ void StreamWrap::OnReadImpl(ssize_t nread,
204204
return;
205205
}
206206

207-
char* base = static_cast<char*>(realloc(buf->base, nread));
207+
char* base = static_cast<char*>(node::Realloc(buf->base, nread));
208208
CHECK_LE(static_cast<size_t>(nread), buf->len);
209209

210210
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
}
@@ -624,7 +624,7 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
624624

625625
case ASCII:
626626
if (contains_non_ascii(buf, buflen)) {
627-
char* out = static_cast<char*>(malloc(buflen));
627+
char* out = static_cast<char*>(node::Malloc(buflen));
628628
if (out == nullptr) {
629629
return Local<String>();
630630
}
@@ -659,7 +659,7 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
659659

660660
case BASE64: {
661661
size_t dlen = base64_encoded_size(buflen);
662-
char* dst = static_cast<char*>(malloc(dlen));
662+
char* dst = static_cast<char*>(node::Malloc(dlen));
663663
if (dst == nullptr) {
664664
return Local<String>();
665665
}
@@ -678,7 +678,7 @@ Local<Value> StringBytes::Encode(Isolate* isolate,
678678

679679
case HEX: {
680680
size_t dlen = buflen * 2;
681-
char* dst = static_cast<char*>(malloc(dlen));
681+
char* dst = static_cast<char*>(node::Malloc(dlen));
682682
if (dst == nullptr) {
683683
return Local<String>();
684684
}

src/tls_wrap.cc

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

662662

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

src/udp_wrap.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
384384
void UDPWrap::OnAlloc(uv_handle_t* handle,
385385
size_t suggested_size,
386386
uv_buf_t* buf) {
387-
buf->base = static_cast<char*>(malloc(suggested_size));
387+
buf->base = static_cast<char*>(node::Malloc(suggested_size));
388388
buf->len = suggested_size;
389389

390390
if (buf->base == nullptr && suggested_size > 0) {
@@ -426,7 +426,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
426426
return;
427427
}
428428

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

src/util-inl.h

+26
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,32 @@ bool StringEqualNoCaseN(const char* a, const char* b, size_t length) {
229229
return true;
230230
}
231231

232+
// These should be used in our code as opposed to the native
233+
// versions as they abstract out some platform and or
234+
// compiler version specific functionality.
235+
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
236+
// that the standard allows them to either return a unique pointer or a
237+
// nullptr for zero-sized allocation requests. Normalize by always using
238+
// a nullptr.
239+
void* Realloc(void* pointer, size_t size) {
240+
if (size == 0) {
241+
free(pointer);
242+
return nullptr;
243+
}
244+
return realloc(pointer, size);
245+
}
246+
247+
// As per spec realloc behaves like malloc if passed nullptr.
248+
void* Malloc(size_t size) {
249+
return Realloc(nullptr, size);
250+
}
251+
252+
void* Calloc(size_t n, size_t size) {
253+
if ((n == 0) || (size == 0)) return nullptr;
254+
CHECK_GE(n * size, n); // Overflow guard.
255+
return calloc(n, size);
256+
}
257+
232258
} // namespace node
233259

234260
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

src/util.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@
2424

2525
namespace node {
2626

27+
// These should be used in our code as opposed to the native
28+
// versions as they abstract out some platform and or
29+
// compiler version specific functionality
30+
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
31+
// that the standard allows them to either return a unique pointer or a
32+
// nullptr for zero-sized allocation requests. Normalize by always using
33+
// 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);
37+
2738
#ifdef __GNUC__
2839
#define NO_RETURN __attribute__((noreturn))
2940
#else
@@ -300,7 +311,7 @@ class MaybeStackBuffer {
300311
// Guard against overflow.
301312
CHECK_LE(storage, sizeof(T) * storage);
302313

303-
buf_ = static_cast<T*>(malloc(sizeof(T) * storage));
314+
buf_ = static_cast<T*>(Malloc(sizeof(T) * storage));
304315
CHECK_NE(buf_, nullptr);
305316
}
306317

0 commit comments

Comments
 (0)