From 350011f5816bb5c9d8d4ef22f93b5989af4763d7 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen <wvo@google.com> Date: Tue, 1 Jul 2014 17:56:12 -0700 Subject: [PATCH] Fixed a bugs in the Java runtime that could cause an index out of bounds exception. Tested: on Windows. Change-Id: I0d4cdafc21690eb9a509ba31f21e80dacfb602ff --- java/flatbuffers/FlatBufferBuilder.java | 20 +++++++++++++------- src/idl_gen_java.cpp | 16 ++++++++++------ tests/JavaTest.bat | 2 +- tests/JavaTest.java | 7 +++++-- tests/MyGame/Example/Any.java | 5 ----- tests/MyGame/Example/Color.java | 5 ----- tests/MyGame/Example/Test.java | 2 +- tests/MyGame/Example/Vec3.java | 4 ++-- 8 files changed, 32 insertions(+), 29 deletions(-) diff --git a/java/flatbuffers/FlatBufferBuilder.java b/java/flatbuffers/FlatBufferBuilder.java index c6864223..ee040178 100755 --- a/java/flatbuffers/FlatBufferBuilder.java +++ b/java/flatbuffers/FlatBufferBuilder.java @@ -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); } } diff --git a/src/idl_gen_java.cpp b/src/idl_gen_java.cpp index 979a80a9..486d2695 100755 --- a/src/idl_gen_java.cpp +++ b/src/idl_gen_java.cpp @@ -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"; - code += "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"; - code += "import flatbuffers.*;\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; } diff --git a/tests/JavaTest.bat b/tests/JavaTest.bat index b8a0b5a0..9ee9c4bd 100755 --- a/tests/JavaTest.bat +++ b/tests/JavaTest.bat @@ -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 diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 86424b18..089e76b5 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -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"); diff --git a/tests/MyGame/Example/Any.java b/tests/MyGame/Example/Any.java index 9cbafb15..7d5a1a00 100755 --- a/tests/MyGame/Example/Any.java +++ b/tests/MyGame/Example/Any.java @@ -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; diff --git a/tests/MyGame/Example/Color.java b/tests/MyGame/Example/Color.java index f983c392..44738ea4 100755 --- a/tests/MyGame/Example/Color.java +++ b/tests/MyGame/Example/Color.java @@ -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; diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java index 1773658b..93261f96 100755 --- a/tests/MyGame/Example/Test.java +++ b/tests/MyGame/Example/Test.java @@ -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); diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java index a71cbccd..652cba94 100755 --- a/tests/MyGame/Example/Vec3.java +++ b/tests/MyGame/Example/Vec3.java @@ -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); -- GitLab