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; ...@@ -28,7 +28,7 @@ import java.nio.charset.Charset;
public class FlatBufferBuilder { public class FlatBufferBuilder {
ByteBuffer bb; // Where we construct the FlatBuffer. ByteBuffer bb; // Where we construct the FlatBuffer.
int space; // Remaining space in the ByteBuffer. 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 minalign = 1; // Minimum alignment encountered so far.
int[] vtable; // The vtable for the current table, null otherwise. int[] vtable; // The vtable for the current table, null otherwise.
int object_start; // Starting offset of the current struct/table. int object_start; // Starting offset of the current struct/table.
...@@ -42,6 +42,7 @@ public class FlatBufferBuilder { ...@@ -42,6 +42,7 @@ public class FlatBufferBuilder {
// Start with a buffer of size `initial_size`, then grow as required. // Start with a buffer of size `initial_size`, then grow as required.
public FlatBufferBuilder(int initial_size) { public FlatBufferBuilder(int initial_size) {
if (initial_size <= 0) initial_size = 1;
space = initial_size; space = initial_size;
bb = newByteBuffer(new byte[initial_size]); bb = newByteBuffer(new byte[initial_size]);
} }
...@@ -57,7 +58,7 @@ public class FlatBufferBuilder { ...@@ -57,7 +58,7 @@ public class FlatBufferBuilder {
ByteBuffer growByteBuffer(ByteBuffer bb) { ByteBuffer growByteBuffer(ByteBuffer bb) {
byte[] old_buf = bb.array(); byte[] old_buf = bb.array();
int old_buf_size = old_buf.length; 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."); throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
int new_buf_size = old_buf_size << 1; int new_buf_size = old_buf_size << 1;
byte[] new_buf = new byte[new_buf_size]; byte[] new_buf = new byte[new_buf_size];
...@@ -135,7 +136,7 @@ public class FlatBufferBuilder { ...@@ -135,7 +136,7 @@ public class FlatBufferBuilder {
public int createString(String s) { public int createString(String s) {
byte[] utf8 = s.getBytes(utf8charset); byte[] utf8 = s.getBytes(utf8charset);
bb.put(--space, (byte)0); addByte((byte)0);
startVector(1, utf8.length); startVector(1, utf8.length);
System.arraycopy(utf8, 0, bb.array(), space -= utf8.length, utf8.length); System.arraycopy(utf8, 0, bb.array(), space -= utf8.length, utf8.length);
return endVector(); return endVector();
...@@ -192,12 +193,12 @@ public class FlatBufferBuilder { ...@@ -192,12 +193,12 @@ public class FlatBufferBuilder {
for (int i = vtable.length - 1; i >= 0 ; i--) { for (int i = vtable.length - 1; i >= 0 ; i--) {
// Offset relative to the start of the table. // Offset relative to the start of the table.
short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0); short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
putShort(off); addShort(off);
} }
final int standard_fields = 2; // The fields below: final int standard_fields = 2; // The fields below:
putShort((short)(vtableloc - object_start)); addShort((short)(vtableloc - object_start));
putShort((short)((vtable.length + standard_fields) * SIZEOF_SHORT)); addShort((short)((vtable.length + standard_fields) * SIZEOF_SHORT));
// Search for an existing vtable that matches the current one. // Search for an existing vtable that matches the current one.
int existing_vtable = 0; int existing_vtable = 0;
...@@ -245,6 +246,11 @@ public class FlatBufferBuilder { ...@@ -245,6 +246,11 @@ public class FlatBufferBuilder {
// The FlatBuffer data doesn't start at offset 0 in the ByteBuffer: // The FlatBuffer data doesn't start at offset 0 in the ByteBuffer:
public int dataStart() { 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, ...@@ -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, static void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
const char *nameprefix) { const char *nameprefix) {
std::string &code = *code_ptr; 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(); for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend(); it != struct_def.fields.vec.rend();
++it) { ++it) {
...@@ -347,7 +348,8 @@ static void GenStruct(StructDef &struct_def, ...@@ -347,7 +348,8 @@ static void GenStruct(StructDef &struct_def,
// Save out the generated code for a single Java class while adding // Save out the generated code for a single Java class while adding
// declaration boilerplate. // declaration boilerplate.
static bool SaveClass(const Parser &parser, const Definition &def, 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; if (!classcode.length()) return true;
std::string name_space_java; std::string name_space_java;
...@@ -365,8 +367,10 @@ static bool SaveClass(const Parser &parser, const Definition &def, ...@@ -365,8 +367,10 @@ static bool SaveClass(const Parser &parser, const Definition &def,
std::string code = "// automatically generated, do not modify\n\n"; std::string code = "// automatically generated, do not modify\n\n";
code += "package " + name_space_java + ";\n\n"; code += "package " + name_space_java + ";\n\n";
code += "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"; if (needs_imports) {
code += "import flatbuffers.*;\n\n"; code += "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n";
code += "import flatbuffers.*;\n\n";
}
code += classcode; code += classcode;
auto filename = name_space_dir + PATH_SEPARATOR + def.name + ".java"; auto filename = name_space_dir + PATH_SEPARATOR + def.name + ".java";
return SaveFile(filename.c_str(), code, false); return SaveFile(filename.c_str(), code, false);
...@@ -383,7 +387,7 @@ bool GenerateJava(const Parser &parser, ...@@ -383,7 +387,7 @@ bool GenerateJava(const Parser &parser,
it != parser.enums_.vec.end(); ++it) { it != parser.enums_.vec.end(); ++it) {
std::string enumcode; std::string enumcode;
GenEnum(**it, &enumcode); GenEnum(**it, &enumcode);
if (!SaveClass(parser, **it, enumcode, path)) if (!SaveClass(parser, **it, enumcode, path, false))
return false; return false;
} }
...@@ -391,7 +395,7 @@ bool GenerateJava(const Parser &parser, ...@@ -391,7 +395,7 @@ bool GenerateJava(const Parser &parser,
it != parser.structs_.vec.end(); ++it) { it != parser.structs_.vec.end(); ++it) {
std::string declcode; std::string declcode;
GenStruct(**it, &declcode, parser.root_struct_def); GenStruct(**it, &declcode, parser.root_struct_def);
if (!SaveClass(parser, **it, declcode, path)) if (!SaveClass(parser, **it, declcode, path, true))
return false; return false;
} }
......
...@@ -17,5 +17,5 @@ rem Compile then run the Java test. ...@@ -17,5 +17,5 @@ rem Compile then run the Java test.
set batch_file_dir=%~d0%~p0 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 java -classpath %batch_file_dir%\..\java;%batch_file_dir% JavaTest
...@@ -44,9 +44,12 @@ class JavaTest { ...@@ -44,9 +44,12 @@ class JavaTest {
TestBuffer(bb, 0); TestBuffer(bb, 0);
// Second, let's create a FlatBuffer from scratch in Java, and test it also. // 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"); int str = fbb.createString("MyMonster");
......
...@@ -2,11 +2,6 @@ ...@@ -2,11 +2,6 @@
package MyGame.Example; package MyGame.Example;
import java.nio.*;
import java.lang.*;
import java.util.*;
import flatbuffers.*;
public class Any { public class Any {
public static final byte NONE = 0; public static final byte NONE = 0;
public static final byte Monster = 1; public static final byte Monster = 1;
......
...@@ -2,11 +2,6 @@ ...@@ -2,11 +2,6 @@
package MyGame.Example; package MyGame.Example;
import java.nio.*;
import java.lang.*;
import java.util.*;
import flatbuffers.*;
public class Color { public class Color {
public static final byte Red = 0; public static final byte Red = 0;
public static final byte Green = 1; public static final byte Green = 1;
......
...@@ -13,7 +13,7 @@ public class Test extends Struct { ...@@ -13,7 +13,7 @@ public class Test extends Struct {
public byte b() { return bb.get(bb_pos + 2); } public byte b() { return bb.get(bb_pos + 2); }
public static int createTest(FlatBufferBuilder builder, short a, byte b) { public static int createTest(FlatBufferBuilder builder, short a, byte b) {
builder.prep(2, 0); builder.prep(2, 4);
builder.pad(1); builder.pad(1);
builder.putByte(b); builder.putByte(b);
builder.putShort(a); builder.putShort(a);
......
...@@ -18,9 +18,9 @@ public class Vec3 extends Struct { ...@@ -18,9 +18,9 @@ public class Vec3 extends Struct {
public Test test3(Test obj) { return obj.__init(bb_pos + 26, bb); } 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) { 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.pad(2);
builder.prep(2, 0); builder.prep(2, 4);
builder.pad(1); builder.pad(1);
builder.putByte(Test_b); builder.putByte(Test_b);
builder.putShort(Test_a); 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