mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-30 13:10:00 +00:00
Fixed a bugs in the Java runtime that could cause an index out of bounds exception.
Tested: on Windows. Change-Id: I0d4cdafc21690eb9a509ba31f21e80dacfb602ff
This commit is contained in:
@@ -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 {
|
|||||||
|
|
||||||
// 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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
// 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,
|
|||||||
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,
|
|||||||
// 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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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.
|
|||||||
|
|
||||||
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 {
|
|||||||
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 @@
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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);
|
||||||
|
|||||||
Reference in New Issue
Block a user