bind/java: ensure there is enough capacity for writing seq

The new testLongString triggers the bug without this change.

Fixes golang/go#9251.

Change-Id: I463e2897b5b08f53801f151c7311d591546c0719
Reviewed-on: https://go-review.googlesource.com/1373
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
David Crawshaw 2014-12-11 12:11:02 -05:00
parent 96c0ef1480
commit 6cf9d880ce
5 changed files with 62 additions and 11 deletions

View File

@ -16,6 +16,28 @@ public class SeqTest extends TestCase {
assertEquals("Unexpected arithmetic failure", 7, res); assertEquals("Unexpected arithmetic failure", 7, res);
} }
public void testShortString() {
String want = "a short string";
String got = Testpkg.StrDup(want);
assertEquals("Strings should match", want, got);
}
public void testLongString() {
StringBuilder b = new StringBuilder();
for (int i = 0; i < 128*1024; i++) {
b.append("0123456789");
}
String want = b.toString();
String got = Testpkg.StrDup(want);
assertEquals("Strings should match", want, got);
}
public void testUnicode() {
String want = "Hello, 世界";
String got = Testpkg.StrDup(want);
assertEquals("Strings should match", want, got);
}
public void testGoRefGC() { public void testGoRefGC() {
Testpkg.S s = Testpkg.New(); Testpkg.S s = Testpkg.New();
runGC(); runGC();

View File

@ -30,21 +30,27 @@ typedef struct mem {
uint32_t cap; uint32_t cap;
} mem; } mem;
static mem *mem_resize(mem *m, uint32_t size) { // mem_ensure ensures that m has at least size bytes free.
// If m is NULL, it is created.
static mem *mem_ensure(mem *m, uint32_t size) {
if (m == NULL) { if (m == NULL) {
m = (mem*)malloc(sizeof(mem)); m = (mem*)malloc(sizeof(mem));
if (m == NULL) { if (m == NULL) {
LOG_FATAL("mem_resize malloc failed"); LOG_FATAL("mem_ensure malloc failed");
} }
m->cap = 0;
m->off = 0; m->off = 0;
m->len = 0; m->len = 0;
m->buf = NULL; m->buf = NULL;
} }
m->buf = (uint8_t*)realloc((void*)m->buf, size); if (m->cap > m->off+size) {
if (m->buf == NULL) { return m;
LOG_FATAL("mem_resize realloc failed, size=%d", size);
} }
m->cap = size; m->buf = (uint8_t*)realloc((void*)m->buf, m->off+size);
if (m->buf == NULL) {
LOG_FATAL("mem_ensure realloc failed, off=%d, size=%d", m->off, size);
}
m->cap = m->off+size;
return m; return m;
} }
@ -78,9 +84,11 @@ uint8_t *mem_write(JNIEnv *env, jobject obj, uint32_t size) {
if (m->off != m->len) { if (m->off != m->len) {
LOG_FATAL("write can only append to seq, size: (off=%d, len=%d, size=%d", m->off, m->len, size); LOG_FATAL("write can only append to seq, size: (off=%d, len=%d, size=%d", m->off, m->len, size);
} }
if (m->off+size > m->cap) { uint32_t cap = m->cap;
m = mem_resize(m, 2*m->cap); while (m->off+size > cap) {
cap *= 2;
} }
m = mem_ensure(m, cap);
uint8_t *res = m->buf+m->off; uint8_t *res = m->buf+m->off;
m->off += size; m->off += size;
m->len += size; m->len += size;
@ -130,8 +138,8 @@ void init_seq(void *javavm) {
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_go_Seq_ensure(JNIEnv *env, jobject obj, jint size) { Java_go_Seq_ensure(JNIEnv *env, jobject obj, jint size) {
mem *m = mem_get(env, obj); mem *m = mem_get(env, obj);
if (m == NULL || size > m->cap - m->off) { if (m == NULL || m->off+size > m->cap) {
m = mem_resize(m, size); m = mem_ensure(m, size);
(*env)->SetLongField(env, obj, memptr_id, (jlong)(uintptr_t)m); (*env)->SetLongField(env, obj, memptr_id, (jlong)(uintptr_t)m);
} }
} }

View File

@ -23,7 +23,6 @@ public abstract class Testpkg {
public static void Call(I i) { public static void Call(I i) {
go.Seq _in = new go.Seq(); go.Seq _in = new go.Seq();
go.Seq _out = new go.Seq(); go.Seq _out = new go.Seq();
System.out.println("Call!");
_in.writeRef(i.ref()); _in.writeRef(i.ref());
Seq.send(DESCRIPTOR, CALL_Call, _in, _out); Seq.send(DESCRIPTOR, CALL_Call, _in, _out);
} }
@ -150,11 +149,22 @@ public abstract class Testpkg {
} }
public static String StrDup(String s) {
go.Seq _in = new go.Seq();
go.Seq _out = new go.Seq();
String _result;
_in.writeUTF16(s);
Seq.send(DESCRIPTOR, CALL_StrDup, _in, _out);
_result = _out.readUTF16();
return _result;
}
private static final int CALL_Add = 1; private static final int CALL_Add = 1;
private static final int CALL_Call = 2; private static final int CALL_Call = 2;
private static final int CALL_GC = 3; private static final int CALL_GC = 3;
private static final int CALL_Keep = 4; private static final int CALL_Keep = 4;
private static final int CALL_New = 5; private static final int CALL_New = 5;
private static final int CALL_NumSCollected = 6; private static final int CALL_NumSCollected = 6;
private static final int CALL_StrDup = 7;
private static final String DESCRIPTOR = "testpkg"; private static final String DESCRIPTOR = "testpkg";
} }

View File

@ -81,6 +81,12 @@ func init() {
seq.Register(proxySDescriptor, proxySFCode, proxySF) seq.Register(proxySDescriptor, proxySFCode, proxySF)
} }
func proxy_StrDup(out, in *seq.Buffer) {
param_s := in.ReadUTF16()
res := testpkg.StrDup(param_s)
out.WriteUTF16(res)
}
func init() { func init() {
seq.Register("testpkg", 1, proxy_Add) seq.Register("testpkg", 1, proxy_Add)
seq.Register("testpkg", 2, proxy_Call) seq.Register("testpkg", 2, proxy_Call)
@ -88,4 +94,5 @@ func init() {
seq.Register("testpkg", 4, proxy_Keep) seq.Register("testpkg", 4, proxy_Keep)
seq.Register("testpkg", 5, proxy_New) seq.Register("testpkg", 5, proxy_New)
seq.Register("testpkg", 6, proxy_NumSCollected) seq.Register("testpkg", 6, proxy_NumSCollected)
seq.Register("testpkg", 7, proxy_StrDup)
} }

View File

@ -56,3 +56,7 @@ func Add(x, y int) int {
func NumSCollected() int { func NumSCollected() int {
return numSCollected return numSCollected
} }
func StrDup(s string) string {
return s
}