Java crashes when closing WDropTargetContextPeerFileStream with heap corruption

Viewed 61

I am currently working on implementing Drag & Drop from Outlook to Swing (on Windows) using a Swing DropTarget. Because Outlook Drag and Drop does no automatically work with Swing, I debugged it and found out it used the FileNameW native for the event. To support this I use this code:

    private static final String nativeFileNameW = "FileNameW";
    private static final DataFlavor fileNameWFlavor = new DataFlavor(InputStream.class, nativeFileNameW);

    public void installFileNameWFlavorIfWindows(DropTarget dt) {
        FlavorMap fm = dt.getFlavorMap();
        if (!(fm instanceof SystemFlavorMap)) {
            fm = SystemFlavorMap.getDefaultFlavorMap();
        }
        if (fm instanceof SystemFlavorMap) {
            SystemFlavorMap sysFM = (SystemFlavorMap) fm;
            sysFM.addFlavorForUnencodedNative(nativeFileNameW, fileNameWFlavor);
            sysFM.addUnencodedNativeForFlavor(fileNameWFlavor, nativeFileNameW);
            dt.setFlavorMap(sysFM);
        }
    }

It seems to work fine, but I am not sure if this is the correct approach, since I couldn't find any resources on this problem.

In the drop event I can now get an InputStream when an Outlook Email is dropped on the Swing Component. I use the following code in my drop method (the real method is more complex, because it also handles other DataFlavors, but this example here can reproduce the error):

public void drop(DropTargetDropEvent dtde) {
    Transferable transfer = dtde.getTransferable();
    boolean accepted = false;
    if (transfer.isDataFlavorSupported(fileNameWFlavor)) {
        accepted = true;
        dtde.acceptDrop(DnDConstants.ACTION_COPY);
        try (InputStream is = (InputStream) transfer.getTransferData(fileNameWFlavor)) {
            //Do something with InputStream
        } catch (UnsupportedFlavorException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    dtde.dropComplete(accepted);
}

I use a try with resource statement to ensure the stream is closed after the drop event. I want to close the stream to make sure there are no open File Handles or similar native resources, that could be limited, after the drop is completed. The InputStream for a Drop from Outlook is an Instance of WDropTargetContextPeerFileStream and when the close method is called, it crashes in the native Method freeStgMedium, which should free the native windows data structure.

I do not get any error output on the command line.
The Program terminates with error code -1073740940 which seems to indicate a heap corruption error.

Is there anything I am missing? Is this InputStream not supposed to be closed or is there a Bug earlier on.

I am using the JDK from Azul, Zulu 8.48.0.53 (Java 8u265).
I have also tried it with Zulu 11, Oracle Java 8 and a Redhat build of Openjdk 8, all fail the same way.

Update: I think I tracked the bug down to JDK native code, that gets the data.

The JDK Code creates a STGMEDIUM object on the stack and passes a Pointer to that to the Windows Method IDataObject::GetData(). This method writes its data back into the STGMEDIUM* parameter.
This should not be a problem, since all examples of this Windows function did it the same way. But it seems, that Outlook does not initialize the member variable IUnknown *STGMEDIUM::pUnkForRelease, but instead relies on the caller to zero-fill the data structure (or Outlook has a Bug).
When the native resources are released by Java, it calls ReleaseStgMedium, which tries to call Release on the pUnkForRelease pointer, if it isn't NULL, which causes the error.

For now, I simply don't close the input stream and let a FileHandle leak, which is not optimal, but I don't see any other solution.

If I find a real solution to this Bug, I will write an Update/Answer here.

0 Answers
Related