Fixed a bugs in the Java runtime that could cause an index out of bounds exception.

Tested: on Windows.

Change-Id: I0d4cdafc21690eb9a509ba31f21e80dacfb602ff
parent 1256307a
......@@ -28,7 +28,7 @@ import java.nio.charset.Charset;
public class FlatBufferBuilder {
ByteBuffer bb; // Where we construct the FlatBuffer.
int space; // Remaining space in the ByteBuffer.
final Charset utf8charset = Charset.forName("UTF-8");
static final Charset utf8charset = Charset.forName("UTF-8");
int minalign = 1; // Minimum alignment encountered so far.
int[] vtable; // The vtable for the current table, null otherwise.
int object_start; // Starting offset of the current struct/table.
......@@ -42,6 +42,7 @@ public class FlatBufferBuilder {
// Start with a buffer of size `initial_size`, then grow as required.
public FlatBufferBuilder(int initial_size) {
if (initial_size <= 0) initial_size = 1;
space = initial_size;
bb = newByteBuffer(new byte[initial_size]);
}
......@@ -57,7 +58,7 @@ public class FlatBufferBuilder {
ByteBuffer growByteBuffer(ByteBuffer bb) {
byte[] old_buf = bb.array();
int old_buf_size = old_buf.length;
if ((old_buf_size & 0xC0000000) != 0)
if ((old_buf_size & 0xC0000000) != 0) // Ensure we don't grow beyond what fits in an int.
throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
int new_buf_size = old_buf_size << 1;
byte[] new_buf = new byte[new_buf_size];
......@@ -135,7 +136,7 @@ public class FlatBufferBuilder {
public int createString(String s) {
byte[] utf8 = s.getBytes(utf8charset);
bb.put(--space, (byte)0);
addByte((byte)0);
startVector(1, utf8.length);
System.arraycopy(utf8, 0, bb.array(), space -= utf8.length, utf8.length);
return endVector();
......@@ -192,12 +193,12 @@ public class FlatBufferBuilder {
for (int i = vtable.length - 1; i >= 0 ; i--) {
// Offset relative to the start of the table.
short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
putShort(off);
addShort(off);
}
final int standard_fields = 2; // The fields below:
putShort((short)(vtableloc - object_start));
putShort((short)((vtable.length + standard_fields) * SIZEOF_SHORT));
addShort((short)(vtableloc - object_start));
addShort((short)((vtable.length + standard_fields) * SIZEOF_SHORT));
// Search for an existing vtable that matches the current one.
int existing_vtable = 0;
......@@ -245,6 +246,11 @@ public class FlatBufferBuilder {
// The FlatBuffer data doesn't start at offset 0 in the ByteBuffer:
public int dataStart() {
return bb.array().length - offset();
return space;
}
// Utility function for copying a byte array that starts at 0.
public byte[] sizedByteArray() {
return Arrays.copyOfRange(bb.array(), dataStart(), bb.array().length);
}
}
......@@ -160,7 +160,8 @@ static void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
static void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
const char *nameprefix) {
std::string &code = *code_ptr;
code += " builder.prep(" + NumToString(struct_def.minalign) + ", 0);\n";
code += " builder.prep(" + NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ");\n";
for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend();
++it) {
......@@ -347,7 +348,8 @@ static void GenStruct(StructDef &struct_def,
// Save out the generated code for a single Java class while adding
// declaration boilerplate.
static bool SaveClass(const Parser &parser, const Definition &def,
const std::string &classcode, const std::string &path) {
const std::string &classcode, const std::string &path,
bool needs_imports) {
if (!classcode.length()) return true;
std::string name_space_java;
......@@ -365,8 +367,10 @@ static bool SaveClass(const Parser &parser, const Definition &def,
std::string code = "// automatically generated, do not modify\n\n";
code += "package " + name_space_java + ";\n\n";
if (needs_imports) {
code += "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n";
code += "import flatbuffers.*;\n\n";
}
code += classcode;
auto filename = name_space_dir + PATH_SEPARATOR + def.name + ".java";
return SaveFile(filename.c_str(), code, false);
......@@ -383,7 +387,7 @@ bool GenerateJava(const Parser &parser,
it != parser.enums_.vec.end(); ++it) {
std::string enumcode;
GenEnum(**it, &enumcode);
if (!SaveClass(parser, **it, enumcode, path))
if (!SaveClass(parser, **it, enumcode, path, false))
return false;
}
......@@ -391,7 +395,7 @@ bool GenerateJava(const Parser &parser,
it != parser.structs_.vec.end(); ++it) {
std::string declcode;
GenStruct(**it, &declcode, parser.root_struct_def);
if (!SaveClass(parser, **it, declcode, path))
if (!SaveClass(parser, **it, declcode, path, true))
return false;
}
......
......@@ -17,5 +17,5 @@ rem Compile then run the Java test.
set batch_file_dir=%~d0%~p0
javac -classpath %batch_file_dir%\..\java;%batch_file_dir% JavaTest.java
javac -g -classpath %batch_file_dir%\..\java;%batch_file_dir% JavaTest.java
java -classpath %batch_file_dir%\..\java;%batch_file_dir% JavaTest
......@@ -44,9 +44,12 @@ class JavaTest {
TestBuffer(bb, 0);
// Second, let's create a FlatBuffer from scratch in Java, and test it also.
// We set up the same values as monsterdata.json:
// We use an initial size of 1 to exercise the reallocation algorithm,
// normally a size larger than the typical FlatBuffer you generate would be
// better for performance.
FlatBufferBuilder fbb = new FlatBufferBuilder(1);
FlatBufferBuilder fbb = new FlatBufferBuilder(1024);
// We set up the same values as monsterdata.json:
int str = fbb.createString("MyMonster");
......
......@@ -2,11 +2,6 @@
package MyGame.Example;
import java.nio.*;
import java.lang.*;
import java.util.*;
import flatbuffers.*;
public class Any {
public static final byte NONE = 0;
public static final byte Monster = 1;
......
......@@ -2,11 +2,6 @@
package MyGame.Example;
import java.nio.*;
import java.lang.*;
import java.util.*;
import flatbuffers.*;
public class Color {
public static final byte Red = 0;
public static final byte Green = 1;
......
......@@ -13,7 +13,7 @@ public class Test extends Struct {
public byte b() { return bb.get(bb_pos + 2); }
public static int createTest(FlatBufferBuilder builder, short a, byte b) {
builder.prep(2, 0);
builder.prep(2, 4);
builder.pad(1);
builder.putByte(b);
builder.putShort(a);
......
......@@ -18,9 +18,9 @@ public class Vec3 extends Struct {
public Test test3(Test obj) { return obj.__init(bb_pos + 26, bb); }
public static int createVec3(FlatBufferBuilder builder, float x, float y, float z, double test1, byte test2, short Test_a, byte Test_b) {
builder.prep(16, 0);
builder.prep(16, 32);
builder.pad(2);
builder.prep(2, 0);
builder.prep(2, 4);
builder.pad(1);
builder.putByte(Test_b);
builder.putShort(Test_a);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment