Skip to content

Commit

Permalink
Fix issue where string references aren't always completed with a null…
Browse files Browse the repository at this point in the history
… terminator.

This is particularly easy to reproduce with an empty string - the
existing implementation works most of the time because most characters
don't consume the full four bytes a single UTF-8 character could
consume.

The tests relies on the fact that two consecutive memory allocations
usually end up next to each other. This happens reliably for me on my
machine, but isn't guaranteed. If there's a better way to test this,
I'd love to hear it.
  • Loading branch information
charleskorn committed Feb 19, 2022
1 parent 9d89e0a commit 152a430
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/main/java/jnr/ffi/Struct.java
Original file line number Diff line number Diff line change
Expand Up @@ -2469,8 +2469,9 @@ public final java.lang.String get() {

public final void set(java.lang.String value) {
if (value != null) {
valueHolder = getRuntime().getMemoryManager().allocateDirect(value.length() * 4);
valueHolder.putString(0, value, value.length() * 4, charset);
int maxBytes = (value.length() * 4) + 1; // Additional byte required for trailing null termination.
valueHolder = getRuntime().getMemoryManager().allocateDirect(maxBytes);
valueHolder.putString(0, value, maxBytes, charset);
getMemory().putPointer(offset(), valueHolder);

} else {
Expand Down
20 changes: 20 additions & 0 deletions src/test/java/jnr/ffi/struct/AsciiStringFieldTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,24 @@ public StructWithStringByRef() {

assertEquals(testValue, struct.stringValue.get());
}

public static final class StructWithConsecutiveStringsByRef extends Struct {
private final AsciiStringRef firstValue = new AsciiStringRef();
private final AsciiStringRef secondValue = new AsciiStringRef();

public StructWithConsecutiveStringsByRef() {
super(runtime);
}
}

@Test public void testStructWithConsecutiveStringsByRef() {
final String testValue = "some test string";
final StructWithConsecutiveStringsByRef struct = new StructWithConsecutiveStringsByRef();

struct.firstValue.set("");
struct.secondValue.set(testValue);

assertEquals("", struct.firstValue.get());
assertEquals(testValue, struct.secondValue.get());
}
}
20 changes: 20 additions & 0 deletions src/test/java/jnr/ffi/struct/UTF8StringFieldTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,24 @@ public StructWithStringByRef() {

assertEquals(testValue, struct.stringValue.get());
}

public static final class StructWithConsecutiveStringsByRef extends Struct {
private final UTF8StringRef firstValue = new UTF8StringRef();
private final UTF8StringRef secondValue = new UTF8StringRef();

public StructWithConsecutiveStringsByRef() {
super(runtime);
}
}

@Test public void testStructWithConsecutiveStringsByRef() {
final String testValue = "some test string";
final StructWithConsecutiveStringsByRef struct = new StructWithConsecutiveStringsByRef();

struct.firstValue.set("");
struct.secondValue.set(testValue);

assertEquals("", struct.firstValue.get());
assertEquals(testValue, struct.secondValue.get());
}
}

0 comments on commit 152a430

Please sign in to comment.