Skip to content

Commit

Permalink
std.uni: add overflow checks to storage allocation
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Aug 2, 2016
1 parent 6db08d3 commit d48c3c3
Showing 1 changed file with 60 additions and 11 deletions.
71 changes: 60 additions & 11 deletions std/uni.d
Original file line number Diff line number Diff line change
Expand Up @@ -1734,7 +1734,13 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
{
import core.stdc.stdlib : malloc;
import std.exception : enforce;
auto ptr = cast(T*)enforce(malloc(T.sizeof*size), "out of memory on C heap");

import core.checkedint : mulu;
bool overflow;
size_t nbytes = mulu(size, T.sizeof, overflow);
if (overflow) assert(0);

auto ptr = cast(T*)enforce(malloc(nbytes), "out of memory on C heap");
return ptr[0..size];
}

Expand All @@ -1747,8 +1753,13 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
destroy(arr);
return null;
}
auto ptr = cast(T*)enforce(realloc(
arr.ptr, T.sizeof*size), "out of memory on C heap");

import core.checkedint : mulu;
bool overflow;
size_t nbytes = mulu(size, T.sizeof, overflow);
if (overflow) assert(0);

auto ptr = cast(T*)enforce(realloc(arr.ptr, nbytes), "out of memory on C heap");
return ptr[0..size];
}

Expand All @@ -1760,17 +1771,43 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
static void append(T, V)(ref T[] arr, V value)
if (!isInputRange!V)
{
if (arr.length == size_t.max) assert(0);
arr = realloc(arr, arr.length+1);
arr[$-1] = force!T(value);
}

@safe unittest
{
int[] arr;
ReallocPolicy.append(arr, 3);

import std.algorithm.comparison : equal;
assert(equal(arr, [3]));
}

static void append(T, V)(ref T[] arr, V value)
if (isInputRange!V && hasLength!V)
{
arr = realloc(arr, arr.length+value.length);
import core.checkedint : addu;
bool overflow;
size_t nelems = addu(arr.length, value.length, overflow);
if (overflow) assert(0);

arr = realloc(arr, nelems);

import std.algorithm.mutation : copy;
copy(value, arr[$-value.length..$]);
}

@safe unittest
{
int[] arr;
ReallocPolicy.append(arr, [1,2,3]);

import std.algorithm.comparison : equal;
assert(equal(arr, [1,2,3]));
}

static void destroy(T)(ref T[] arr)
{
import core.stdc.stdlib : free;
Expand Down Expand Up @@ -6690,7 +6727,7 @@ public:
import core.stdc.stdlib : realloc;
if (!isBig)
{
if (slen_ + 1 > small_cap)
if (slen_ == small_cap)
convertToBig();// & fallthrough to "big" branch
else
{
Expand All @@ -6701,10 +6738,15 @@ public:
}

assert(isBig);
if (len_ + 1 > cap_)
if (len_ == cap_)
{
cap_ += grow;
ptr_ = cast(ubyte*)enforce(realloc(ptr_, 3*(cap_+1)),
import core.checkedint : addu, mulu;
bool overflow;
cap_ = addu(cap_, grow, overflow);
auto nelems = mulu(3, addu(cap_, 1, overflow), overflow);
if (overflow) assert(0);

ptr_ = cast(ubyte*)enforce(realloc(ptr_, nelems),
"realloc failed");
}
write24(ptr_, ch, len_++);
Expand Down Expand Up @@ -6765,7 +6807,11 @@ public:
import core.stdc.stdlib : malloc;
if (isBig)
{// dup it
auto raw_cap = 3*(cap_+1);
import core.checkedint : addu, mulu;
bool overflow;
auto raw_cap = mulu(3, addu(cap_, 1, overflow), overflow);
if (overflow) assert(0);

auto p = cast(ubyte*)enforce(malloc(raw_cap), "malloc failed");
p[0..raw_cap] = ptr_[0..raw_cap];
ptr_ = p;
Expand Down Expand Up @@ -6809,8 +6855,11 @@ private:
void convertToBig()
{
import core.stdc.stdlib : malloc;
immutable k = smallLength;
ubyte* p = cast(ubyte*)enforce(malloc(3*(grow+1)), "malloc failed");

static assert(grow.max / 3 - 1 >= grow);
enum nbytes = 3 * (grow + 1);
size_t k = smallLength;
ubyte* p = cast(ubyte*)enforce(malloc(nbytes), "malloc failed");
for (int i=0; i<k; i++)
write24(p, read24(small_.ptr, i), i);
// now we can overwrite small array data
Expand Down

0 comments on commit d48c3c3

Please sign in to comment.