Bug 1531638 - Make Vector::begin() always return a non-null pointer, to accommodate users that need/want this. r=froydnj

Differential Revision: https://phabricator.services.mozilla.com/D21825

--HG--
extra : rebase_source : 5682d209aef3c10b204678c8865758708f2a7e3e
This commit is contained in:
Jeff Walden 2019-02-28 21:30:49 -08:00
parent a18b131623
commit 70e73da609
2 changed files with 70 additions and 1 deletions

View File

@ -403,7 +403,14 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy {
: CapacityAndReserved(aCapacity, aReserved) {}
CRAndStorage() = default;
T* storage() { return nullptr; }
T* storage() {
// If this returns |nullptr|, functions like |Vector::begin()| would too,
// breaking callers that pass a vector's elements as pointer/length to
// code that bounds its operation by length but (even just as a sanity
// check) always wants a non-null pointer. Fake up an aligned, non-null
// pointer to support these callers.
return reinterpret_cast<T*>(sizeof(T));
}
};
CRAndStorage<kInlineCapacity, 0> mTail;

View File

@ -506,6 +506,67 @@ static_assert(sizeof(Vector<Incomplete, 0>) ==
#endif // DEBUG
static void TestVectorBeginNonNull() {
// Vector::begin() should never return nullptr, to accommodate callers that
// (either for hygiene, or for semantic reasons) need a non-null pointer even
// for zero elements.
Vector<bool, 0> bvec0;
MOZ_RELEASE_ASSERT(bvec0.length() == 0);
MOZ_RELEASE_ASSERT(bvec0.begin() != nullptr);
Vector<bool, 1> bvec1;
MOZ_RELEASE_ASSERT(bvec1.length() == 0);
MOZ_RELEASE_ASSERT(bvec1.begin() != nullptr);
Vector<bool, 64> bvec64;
MOZ_RELEASE_ASSERT(bvec64.length() == 0);
MOZ_RELEASE_ASSERT(bvec64.begin() != nullptr);
Vector<int, 0> ivec0;
MOZ_RELEASE_ASSERT(ivec0.length() == 0);
MOZ_RELEASE_ASSERT(ivec0.begin() != nullptr);
Vector<int, 1> ivec1;
MOZ_RELEASE_ASSERT(ivec1.length() == 0);
MOZ_RELEASE_ASSERT(ivec1.begin() != nullptr);
Vector<int, 64> ivec64;
MOZ_RELEASE_ASSERT(ivec64.length() == 0);
MOZ_RELEASE_ASSERT(ivec64.begin() != nullptr);
Vector<long, 0> lvec0;
MOZ_RELEASE_ASSERT(lvec0.length() == 0);
MOZ_RELEASE_ASSERT(lvec0.begin() != nullptr);
Vector<long, 1> lvec1;
MOZ_RELEASE_ASSERT(lvec1.length() == 0);
MOZ_RELEASE_ASSERT(lvec1.begin() != nullptr);
Vector<long, 64> lvec64;
MOZ_RELEASE_ASSERT(lvec64.length() == 0);
MOZ_RELEASE_ASSERT(lvec64.begin() != nullptr);
// Vector<T, N> doesn't guarantee N inline elements -- the actual count is
// capped so that any Vector fits in a not-crazy amount of space -- so the
// code below won't overflow stacks or anything crazy.
struct VeryBig {
int array[16 * 1024 * 1024];
};
Vector<VeryBig, 0> vbvec0;
MOZ_RELEASE_ASSERT(vbvec0.length() == 0);
MOZ_RELEASE_ASSERT(vbvec0.begin() != nullptr);
Vector<VeryBig, 1> vbvec1;
MOZ_RELEASE_ASSERT(vbvec1.length() == 0);
MOZ_RELEASE_ASSERT(vbvec1.begin() != nullptr);
Vector<VeryBig, 64> vbvec64;
MOZ_RELEASE_ASSERT(vbvec64.length() == 0);
MOZ_RELEASE_ASSERT(vbvec64.begin() != nullptr);
}
int main() {
VectorTesting::testReserved();
VectorTesting::testConstRange();
@ -516,4 +577,5 @@ int main() {
VectorTesting::testReplaceRawBuffer();
VectorTesting::testInsert();
VectorTesting::testPodResizeToFit();
TestVectorBeginNonNull();
}