Skip to content

Commit d66e9e9

Browse files
committed
avoid crash with really long strings
1 parent a3994e0 commit d66e9e9

File tree

4 files changed

+84
-21
lines changed

4 files changed

+84
-21
lines changed

Diff for: CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Bug Fixes
2929
* Fix structure alignment issues on linux/ppc.
3030
* Fix structure alignment issues on linux/arm.
3131
* Account for NIO Buffer position (JIRA issue 185).
32+
* Avoid crash with very long Strings (> 150k in length).
3233

3334
Release 3.3.0
3435
=============

Diff for: build.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@
402402
<condition property="make.BUILD" value="BUILD=../${build}/native" else="BUILD=${build.native}">
403403
<os family="windows"/>
404404
</condition>
405-
<condition property="make.PATH" value="PATH=/usr/sfw/bin:/usr/bin:/usr/ccs/bin" else="IGNORE=">
405+
<condition property="make.PATH" value="PATH=/opt/csw/bin:/usr/sfw/bin:/usr/bin:/usr/ccs/bin" else="IGNORE=">
406406
<os name="SunOS"/>
407407
</condition>
408408
<condition property="make" value="/usr/sfw/bin/gmake">
@@ -711,6 +711,8 @@ processor=arm;osname=linux,
711711
com/sun/jna/linux-ia64/libjnidispatch.so;
712712
processor=ia64;osname=linux,
713713
714+
com/sun/jna/openbsd-i386/libjnidispatch.so;
715+
processor=x86;osname=openbsd,
714716
com/sun/jna/freebsd-i386/libjnidispatch.so;
715717
processor=x86;osname=freebsd,
716718
com/sun/jna/freebsd-amd64/libjnidispatch.so;

Diff for: native/dispatch.c

+65-20
Original file line numberDiff line numberDiff line change
@@ -577,18 +577,33 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray arr,
577577
}
578578
}
579579

580+
/** Copy characters from the Java character array into native memory. */
580581
static void
581582
getChars(JNIEnv* env, wchar_t* dst, jcharArray chars, jint off, jint len) {
582583
PSTART();
584+
583585
if (sizeof(jchar) == sizeof(wchar_t)) {
584586
(*env)->GetCharArrayRegion(env, chars, off, len, (jchar*)dst);
585587
}
586588
else {
587-
int i;
588-
jchar* buf = (jchar *)alloca(len * sizeof(jchar));
589-
(*env)->GetCharArrayRegion(env, chars, off, len, buf);
590-
for (i=0;i < len;i++) {
591-
dst[i] = (wchar_t)buf[i];
589+
jchar* buf;
590+
int count = len > 1000 ? 1000 : len;
591+
buf = (jchar *)alloca(count * sizeof(jchar));
592+
if (!buf) {
593+
throwByName(env, EOutOfMemory, "Can't read characters");
594+
}
595+
else {
596+
while (len > 0) {
597+
int i;
598+
(*env)->GetCharArrayRegion(env, chars, off, count, buf);
599+
for (i=0;i < count;i++) {
600+
dst[i] = (wchar_t)buf[i];
601+
}
602+
dst += count;
603+
off += count;
604+
len -= count;
605+
if (count > len) count = len;
606+
}
592607
}
593608
}
594609
PEND();
@@ -597,16 +612,31 @@ getChars(JNIEnv* env, wchar_t* dst, jcharArray chars, jint off, jint len) {
597612
static void
598613
setChars(JNIEnv* env, wchar_t* src, jcharArray chars, jint off, jint len) {
599614
jchar* buf = (jchar*)src;
615+
int malloced = 0;
600616
PSTART();
601617

602-
if (sizeof(jchar) != sizeof(wchar_t)) {
603-
int i;
604-
buf = (jchar *)alloca(len * sizeof(jchar));
605-
for (i=0;i < len;i++) {
606-
buf[i] = (jchar)src[i];
618+
if (sizeof(jchar) == sizeof(wchar_t)) {
619+
(*env)->SetCharArrayRegion(env, chars, off, len, buf);
620+
}
621+
else {
622+
int count = len > 1000 ? 1000 : len;
623+
buf = (jchar *)alloca(count * sizeof(jchar));
624+
if (!buf) {
625+
throwByName(env, EOutOfMemory, "Can't write characters");
626+
}
627+
else {
628+
while (len > 0) {
629+
int i;
630+
for (i=0;i < count;i++) {
631+
buf[i] = (jchar)src[off+i];
632+
}
633+
(*env)->SetCharArrayRegion(env, chars, off, count, buf);
634+
off += count;
635+
len -= count;
636+
if (count > len) count = len;
637+
}
607638
}
608639
}
609-
(*env)->SetCharArrayRegion(env, chars, off, len, buf);
610640
PEND();
611641
}
612642

@@ -690,7 +720,13 @@ newWideCString(JNIEnv *env, jstring str)
690720
}
691721
// TODO: ensure proper encoding conversion from jchar to native wchar_t
692722
getChars(env, result, chars, 0, len);
693-
result[len] = 0; /* NUL-terminate */
723+
if ((*env)->ExceptionCheck(env)) {
724+
free((void *)result);
725+
result = NULL;
726+
}
727+
else {
728+
result[len] = 0; /* NUL-terminate */
729+
}
694730
}
695731
(*env)->DeleteLocalRef(env, chars);
696732
return result;
@@ -722,14 +758,22 @@ newJavaString(JNIEnv *env, const char *ptr, jboolean wide)
722758
if (ptr) {
723759
if (wide) {
724760
// TODO: proper conversion from native wchar_t to jchar, if any
725-
int len = (int)wcslen((const wchar_t*)ptr);
761+
jsize len = (int)wcslen((const wchar_t*)ptr);
726762
if (sizeof(jchar) != sizeof(wchar_t)) {
727-
jchar* buf = (jchar*)alloca(len * sizeof(jchar));
728-
int i;
729-
for (i=0;i < len;i++) {
730-
buf[i] = *((const wchar_t*)ptr + i);
763+
// NOTE: while alloca may succeed here, writing to the stack
764+
// memory may fail with really large buffers
765+
jchar* buf = (jchar*)malloc(len * sizeof(jchar));
766+
if (!buf) {
767+
throwByName(env, EOutOfMemory, "Can't allocate space for conversion to Java String");
768+
}
769+
else {
770+
int i;
771+
for (i=0;i < len;i++) {
772+
buf[i] = *((const wchar_t*)ptr + i);
773+
}
774+
result = (*env)->NewString(env, buf, len);
775+
free((void*)buf);
731776
}
732-
result = (*env)->NewString(env, buf, len);
733777
}
734778
else {
735779
result = (*env)->NewString(env, (const jchar*)ptr, len);
@@ -1166,8 +1210,9 @@ get_system_property(JNIEnv* env, const char* name, jboolean wide) {
11661210
jstring value = (*env)->CallStaticObjectMethod(env, classSystem,
11671211
mid, propname);
11681212
if (value) {
1169-
if (wide)
1213+
if (wide) {
11701214
return newWideCString(env, value);
1215+
}
11711216
return newCStringUTF8(env, value);
11721217
}
11731218
}
@@ -2751,7 +2796,7 @@ Java_com_sun_jna_Native_getWindowHandle0(JNIEnv *env, jclass UNUSED(classp), job
27512796
#else
27522797
swprintf(path, L"%s%s", prop, suffix);
27532798
#endif
2754-
free(prop);
2799+
free((void *)prop);
27552800
}
27562801
#undef JAWT_NAME
27572802
#define JAWT_NAME path

Diff for: test/com/sun/jna/NativeTest.java

+15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@
2121
//@SuppressWarnings("unused")
2222
public class NativeTest extends TestCase {
2323

24+
public void testLongStringGeneration() {
25+
StringBuffer buf = new StringBuffer();
26+
final int MAX = 2000000;
27+
for (int i=0;i < MAX;i++) {
28+
buf.append('a');
29+
}
30+
String s1 = buf.toString();
31+
Memory m = new Memory((MAX + 1)*Native.WCHAR_SIZE);
32+
m.setString(0, s1, true);
33+
assertEquals("Missing terminator after write", 0, m.getChar(MAX*Native.WCHAR_SIZE));
34+
String s2 = m.getString(0, true);
35+
assertEquals("Wrong string read length", s1.length(), s2.length());
36+
assertEquals("Improper wide string read", s1, s2);
37+
}
38+
2439
public void testDefaultStringEncoding() throws Exception {
2540
String encoding = System.getProperty("file.encoding");
2641
// Keep stuff within the extended ASCII range so we work with more

0 commit comments

Comments
 (0)