Add runtime checks for vector size in Java

It doesn't seem to be possible to have a Java collection with more than 2^31-1
items, but it is perfectly possible to have an std::vector with more elements
than that in C++, so add runtime checks verifying that we don't lose count of
elements in the Java wrappers.
This commit is contained in:
Vadim Zeitlin 2016-11-29 00:20:24 +01:00
commit eba70ed16f

View file

@ -7,6 +7,27 @@
%{
#include <vector>
#include <stdexcept>
#include <climits>
// C++ allows to have up to 2^64-1 items in a vector on 64 bit machines and
// 2^32-1 even on 32 bit ones, but in Java size() must return a value of type
// "int" which is limited to signed 32 bit values, i.e. 2^31-1, and there
// doesn't seem to be any way to represent bigger vectors there.
//
// The only thing we can do is to at least detect such situation and throw an
// exception instead of silently returning the wrong size in this case and we
// use this helper to convert size_t values to int, instead of just casting
// them, in order to achieve this.
namespace {
int size_as_int(std::size_t sz) {
if (sz > static_cast<std::size_t>(INT_MAX)) {
throw std::out_of_range("vector size is too big to be representable as int");
}
return static_cast<int>(sz);
}
} // anonymous namespace
%}
%define SWIG_STD_VECTOR_MINIMUM_INTERNAL(CTYPE, CREF_TYPE)
@ -55,6 +76,10 @@
modCount++;
doRemoveRange(fromIndex, toIndex);
}
public int size() {
return doSize();
}
%}
public:
@ -63,21 +88,22 @@
typedef CREF_TYPE const_reference;
vector();
vector(size_type n);
// Note that it returns int, and not size_type, for compatibility with
// the signature of size() in Java interface.
int size() const;
size_type capacity() const;
void reserve(size_type n);
%rename(isEmpty) empty;
bool empty() const;
void clear();
%extend {
int doSize() const {
return size_as_int(self->size());
}
void doAdd(const value_type& value) {
self->push_back(value);
}
void doAdd(int index, const value_type& value) throw (std::out_of_range) {
const int size = int(self->size());
const int size = size_as_int(self->size());
if (0 <= index && index <= size) {
self->insert(self->begin() + index, value);
} else {
@ -85,7 +111,7 @@
}
}
value_type doRemove(int index) throw (std::out_of_range) {
const int size = int(self->size());
const int size = size_as_int(self->size());
if (0 <= index && index < size) {
CTYPE const old_value = (*self)[index];
self->erase(self->begin() + index);
@ -95,14 +121,14 @@
}
}
CREF_TYPE doGet(int i) throw (std::out_of_range) {
int size = int(self->size());
const int size = size_as_int(self->size());
if (i>=0 && i<size)
return (*self)[i];
else
throw std::out_of_range("vector index out of range");
}
value_type doSet(int i, const value_type& val) throw (std::out_of_range) {
int size = int(self->size());
const int size = size_as_int(self->size());
if (i>=0 && i<size) {
CTYPE const old_value = (*self)[i];
(*self)[i] = val;
@ -112,7 +138,7 @@
throw std::out_of_range("vector index out of range");
}
void doRemoveRange(int fromIndex, int toIndex) throw (std::out_of_range) {
const int size = int(self->size());
const int size = size_as_int(self->size());
if (0 <= fromIndex && fromIndex <= toIndex && toIndex <= size) {
self->erase(self->begin() + fromIndex, self->begin() + toIndex);
} else {