Skip to content

Commit

Permalink
avoid crash with really long strings
Browse files Browse the repository at this point in the history
  • Loading branch information
twall committed Nov 7, 2011
1 parent a3994e0 commit d66e9e9
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Bug Fixes
* Fix structure alignment issues on linux/ppc.
* Fix structure alignment issues on linux/arm.
* Account for NIO Buffer position (JIRA issue 185).
* Avoid crash with very long Strings (> 150k in length).

Release 3.3.0
=============
Expand Down
4 changes: 3 additions & 1 deletion build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@
<condition property="make.BUILD" value="BUILD=../${build}/native" else="BUILD=${build.native}">
<os family="windows"/>
</condition>
<condition property="make.PATH" value="PATH=/usr/sfw/bin:/usr/bin:/usr/ccs/bin" else="IGNORE=">
<condition property="make.PATH" value="PATH=/opt/csw/bin:/usr/sfw/bin:/usr/bin:/usr/ccs/bin" else="IGNORE=">
<os name="SunOS"/>
</condition>
<condition property="make" value="/usr/sfw/bin/gmake">
Expand Down Expand Up @@ -711,6 +711,8 @@ processor=arm;osname=linux,
com/sun/jna/linux-ia64/libjnidispatch.so;
processor=ia64;osname=linux,
com/sun/jna/openbsd-i386/libjnidispatch.so;
processor=x86;osname=openbsd,
com/sun/jna/freebsd-i386/libjnidispatch.so;
processor=x86;osname=freebsd,
com/sun/jna/freebsd-amd64/libjnidispatch.so;
Expand Down
85 changes: 65 additions & 20 deletions native/dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,18 +577,33 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray arr,
}
}

/** Copy characters from the Java character array into native memory. */
static void
getChars(JNIEnv* env, wchar_t* dst, jcharArray chars, jint off, jint len) {
PSTART();

if (sizeof(jchar) == sizeof(wchar_t)) {
(*env)->GetCharArrayRegion(env, chars, off, len, (jchar*)dst);
}
else {
int i;
jchar* buf = (jchar *)alloca(len * sizeof(jchar));
(*env)->GetCharArrayRegion(env, chars, off, len, buf);
for (i=0;i < len;i++) {
dst[i] = (wchar_t)buf[i];
jchar* buf;
int count = len > 1000 ? 1000 : len;
buf = (jchar *)alloca(count * sizeof(jchar));
if (!buf) {
throwByName(env, EOutOfMemory, "Can't read characters");
}
else {
while (len > 0) {
int i;
(*env)->GetCharArrayRegion(env, chars, off, count, buf);
for (i=0;i < count;i++) {
dst[i] = (wchar_t)buf[i];
}
dst += count;
off += count;
len -= count;
if (count > len) count = len;
}
}
}
PEND();
Expand All @@ -597,16 +612,31 @@ getChars(JNIEnv* env, wchar_t* dst, jcharArray chars, jint off, jint len) {
static void
setChars(JNIEnv* env, wchar_t* src, jcharArray chars, jint off, jint len) {
jchar* buf = (jchar*)src;
int malloced = 0;
PSTART();

if (sizeof(jchar) != sizeof(wchar_t)) {
int i;
buf = (jchar *)alloca(len * sizeof(jchar));
for (i=0;i < len;i++) {
buf[i] = (jchar)src[i];
if (sizeof(jchar) == sizeof(wchar_t)) {
(*env)->SetCharArrayRegion(env, chars, off, len, buf);
}
else {
int count = len > 1000 ? 1000 : len;
buf = (jchar *)alloca(count * sizeof(jchar));
if (!buf) {
throwByName(env, EOutOfMemory, "Can't write characters");
}
else {
while (len > 0) {
int i;
for (i=0;i < count;i++) {
buf[i] = (jchar)src[off+i];
}
(*env)->SetCharArrayRegion(env, chars, off, count, buf);
off += count;
len -= count;
if (count > len) count = len;
}
}
}
(*env)->SetCharArrayRegion(env, chars, off, len, buf);
PEND();
}

Expand Down Expand Up @@ -690,7 +720,13 @@ newWideCString(JNIEnv *env, jstring str)
}
// TODO: ensure proper encoding conversion from jchar to native wchar_t
getChars(env, result, chars, 0, len);
result[len] = 0; /* NUL-terminate */
if ((*env)->ExceptionCheck(env)) {
free((void *)result);
result = NULL;
}
else {
result[len] = 0; /* NUL-terminate */
}
}
(*env)->DeleteLocalRef(env, chars);
return result;
Expand Down Expand Up @@ -722,14 +758,22 @@ newJavaString(JNIEnv *env, const char *ptr, jboolean wide)
if (ptr) {
if (wide) {
// TODO: proper conversion from native wchar_t to jchar, if any
int len = (int)wcslen((const wchar_t*)ptr);
jsize len = (int)wcslen((const wchar_t*)ptr);
if (sizeof(jchar) != sizeof(wchar_t)) {
jchar* buf = (jchar*)alloca(len * sizeof(jchar));
int i;
for (i=0;i < len;i++) {
buf[i] = *((const wchar_t*)ptr + i);
// NOTE: while alloca may succeed here, writing to the stack
// memory may fail with really large buffers
jchar* buf = (jchar*)malloc(len * sizeof(jchar));
if (!buf) {
throwByName(env, EOutOfMemory, "Can't allocate space for conversion to Java String");
}
else {
int i;
for (i=0;i < len;i++) {
buf[i] = *((const wchar_t*)ptr + i);
}
result = (*env)->NewString(env, buf, len);
free((void*)buf);
}
result = (*env)->NewString(env, buf, len);
}
else {
result = (*env)->NewString(env, (const jchar*)ptr, len);
Expand Down Expand Up @@ -1166,8 +1210,9 @@ get_system_property(JNIEnv* env, const char* name, jboolean wide) {
jstring value = (*env)->CallStaticObjectMethod(env, classSystem,
mid, propname);
if (value) {
if (wide)
if (wide) {
return newWideCString(env, value);
}
return newCStringUTF8(env, value);
}
}
Expand Down Expand Up @@ -2751,7 +2796,7 @@ Java_com_sun_jna_Native_getWindowHandle0(JNIEnv *env, jclass UNUSED(classp), job
#else
swprintf(path, L"%s%s", prop, suffix);
#endif
free(prop);
free((void *)prop);
}
#undef JAWT_NAME
#define JAWT_NAME path
Expand Down
15 changes: 15 additions & 0 deletions test/com/sun/jna/NativeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@
//@SuppressWarnings("unused")
public class NativeTest extends TestCase {

public void testLongStringGeneration() {
StringBuffer buf = new StringBuffer();
final int MAX = 2000000;
for (int i=0;i < MAX;i++) {
buf.append('a');
}
String s1 = buf.toString();
Memory m = new Memory((MAX + 1)*Native.WCHAR_SIZE);
m.setString(0, s1, true);
assertEquals("Missing terminator after write", 0, m.getChar(MAX*Native.WCHAR_SIZE));
String s2 = m.getString(0, true);
assertEquals("Wrong string read length", s1.length(), s2.length());
assertEquals("Improper wide string read", s1, s2);
}

public void testDefaultStringEncoding() throws Exception {
String encoding = System.getProperty("file.encoding");
// Keep stuff within the extended ASCII range so we work with more
Expand Down

0 comments on commit d66e9e9

Please sign in to comment.