Skip to content

Premature GC of Pointer object when invoking getWideString #664

@rprichard

Description

@rprichard

(Copied from jna-users forum post on 2015-12-23, https://groups.google.com/forum/#!topic/jna-users/dCPnztnQnRw.)


I compiled JNA myself, and when I ran the test suite, the testLongStringGeneration(com.sun.jna.NativeTest) test sometimes failed with a "Invalid memory access" error indicating a JVM segfault. Here's what it looks like running JUnit from the command-line:

C:\rprichard\work\jna>c:\java\jdk1.8.0_60\bin\java -cp "build/jna.jar;build/jna-test.jar;lib/junit.jar;lib/hamcrest-core-1.3.jar" org.junit.runner.JUnitCore com.sun.jna.NativeTest
JUnit version 4.11
............E..E........JNA Warning: Encoding 'unsupported' is unsupported
JNA Warning: Encoding with fallback Cp1252
.......E
Time: 0.374
There were 3 failures:
1) testSynchronizedAccess(com.sun.jna.NativeTest)
java.lang.UnsatisfiedLinkError: Unable to load library 'testlib': Native library (win32-x86/testlib.dll) not found in re
source path ([file:/C:/rprichard/work/jna/build/jna.jar, file:/C:/rprichard/work/jna/build/jna-test.jar, file:/C:/rprich
ard/work/jna/lib/junit.jar, file:/C:/rprichard/work/jna/lib/hamcrest-core-1.3.jar])

... elided ... (test setup issue)

2) testOptionsInferenceFromInstanceField(com.sun.jna.NativeTest)
java.lang.UnsatisfiedLinkError: Unable to load library 'testlib': Native library (win32-x86/testlib.dll) not found in re
source path ([file:/C:/rprichard/work/jna/build/jna.jar, file:/C:/rprichard/work/jna/build/jna-test.jar, file:/C:/rprich
ard/work/jna/lib/junit.jar, file:/C:/rprichard/work/jna/lib/hamcrest-core-1.3.jar])

... elided ... (test setup issue)

3) testLongStringGeneration(com.sun.jna.NativeTest)
java.lang.Error: Invalid memory access
        at com.sun.jna.Native.getWideString(Native Method)
        at com.sun.jna.Pointer.getWideString(Pointer.java:696)
        at com.sun.jna.Memory.getWideString(Memory.java:561)
        at com.sun.jna.NativeTest.testLongStringGeneration(NativeTest.java:77)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at junit.framework.TestCase.runTest(TestCase.java:176)
        at junit.framework.TestCase.runBare(TestCase.java:141)
        at junit.framework.TestResult$1.protect(TestResult.java:122)
        at junit.framework.TestResult.runProtected(TestResult.java:142)
        at junit.framework.TestResult.run(TestResult.java:125)
        at junit.framework.TestCase.run(TestCase.java:129)
        at junit.framework.TestSuite.runTest(TestSuite.java:255)
        at junit.framework.TestSuite.run(TestSuite.java:250)
        at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84)
        at org.junit.runners.Suite.runChild(Suite.java:127)
        at org.junit.runners.Suite.runChild(Suite.java:26)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
        at org.junit.runner.JUnitCore.runMain(JUnitCore.java:96)
        at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:47)
        at org.junit.runner.JUnitCore.main(JUnitCore.java:40)

FAILURES!!!
Tests run: 29,  Failures: 3

I'm using 32-bit Windows 7 SP1, with jdk1.8.0_60.

I worked on the test a bit, and came up with this standalone test program that segfaults using the official JNA 4.2.1 JAR.

package com.example;
import com.sun.jna.Memory;
import com.sun.jna.Native;

public class JnaTest {
    public static void main(String[] args) {
        // This code below is reduced from a different test.  (I forget which.)
        new Memory(4);

        // The code below comes from NativeTest.testLongStringGeneration.
        StringBuilder buf = new StringBuilder();
        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.setWideString(0, s1);
        m.getWideString(0);
    }
}

C:\rprichard\proj\JnaTest>c:\Java\jdk1.8.0_60\bin\java.exe -cp build\classes\main;lib\jna-4.2.1.jar com.example.JnaTest
Exception in thread "main" java.lang.Error: Invalid memory access
        at com.sun.jna.Native.getWideString(Native Method)
        at com.sun.jna.Pointer.getWideString(Pointer.java:696)
        at com.sun.jna.Memory.getWideString(Memory.java:561)
        at com.example.JnaTest.main(JnaTest.java:19)

With lots of printf debugging, I think I identified the cause. The final m.getWideString call ultimately calls Java_com_sun_jna_Native_getWideString. Once the JVM reaches this native function, there are no live references remaining to the Memory object. newJavaString calls back into the JVM, ((*env)->NewString), to create the 2MB String object, at which point the JVM finalizes the Memory object, which frees the buffer. The JVM then attempts to read from the freed buffer and segfaults.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions