1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @enablePreview 27 * @requires jdk.foreign.linker != "UNSUPPORTED" 28 * @modules java.base/jdk.internal.foreign 29 * @run testng/othervm --enable-native-access=ALL-UNNAMED TestIllegalLink 30 */ 31 32 import java.lang.foreign.Arena; 33 import java.lang.foreign.Linker; 34 import java.lang.foreign.FunctionDescriptor; 35 import java.lang.foreign.MemorySegment; 36 import java.lang.foreign.MemoryLayout; 37 import java.lang.foreign.ValueLayout; 38 import java.lang.invoke.MethodHandle; 39 import java.lang.invoke.MethodHandles; 40 import java.lang.invoke.MethodType; 41 import java.nio.ByteOrder; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.List; 45 46 import jdk.internal.foreign.CABI; 47 import org.testng.annotations.DataProvider; 48 import org.testng.annotations.Test; 49 50 import static org.testng.Assert.assertTrue; 51 import static org.testng.Assert.fail; 52 53 public class TestIllegalLink extends NativeTestHelper { 54 55 private static final boolean IS_SYSV = CABI.current() == CABI.SYS_V; 56 private static final boolean IS_LE = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; 57 58 private static final MemorySegment DUMMY_TARGET = MemorySegment.ofAddress(1); 59 private static final MethodHandle DUMMY_TARGET_MH = MethodHandles.empty(MethodType.methodType(void.class)); 60 private static final Linker ABI = Linker.nativeLinker(); 61 62 @Test(dataProvider = "types") 63 public void testIllegalLayouts(FunctionDescriptor desc, Linker.Option[] options, String expectedExceptionMessage) { 64 try { 65 ABI.downcallHandle(DUMMY_TARGET, desc, options); 66 fail("Expected IllegalArgumentException was not thrown"); 67 } catch (IllegalArgumentException e) { 68 assertTrue(e.getMessage().contains(expectedExceptionMessage), 69 e.getMessage() + " does not contain " + expectedExceptionMessage); 70 } 71 } 72 73 @Test(dataProvider = "downcallOnlyOptions", 74 expectedExceptions = IllegalArgumentException.class, 75 expectedExceptionsMessageRegExp = ".*Not supported for upcall.*") 76 public void testIllegalUpcallOptions(Linker.Option downcallOnlyOption) { 77 ABI.upcallStub(DUMMY_TARGET_MH, FunctionDescriptor.ofVoid(), Arena.ofAuto(), downcallOnlyOption); 78 } 79 80 @Test(dataProvider = "illegalCaptureState", 81 expectedExceptions = IllegalArgumentException.class, 82 expectedExceptionsMessageRegExp = ".*Unknown name.*") 83 public void testIllegalCaptureState(String name) { 84 Linker.Option.captureCallState(name); 85 } 86 87 // where 88 89 @DataProvider 90 public static Object[][] illegalCaptureState() { 91 if (!IS_WINDOWS) { 92 return new Object[][]{ 93 { "GetLastError" }, 94 { "WSAGetLastError" }, 95 }; 96 } 97 return new Object[][]{}; 98 } 99 100 @DataProvider 101 public static Object[][] downcallOnlyOptions() { 102 return new Object[][]{ 103 { Linker.Option.firstVariadicArg(0) }, 104 { Linker.Option.captureCallState("errno") }, 105 { Linker.Option.isTrivial() }, 106 }; 107 } 108 109 @DataProvider 110 public static Object[][] types() { 111 Linker.Option[] NO_OPTIONS = new Linker.Option[0]; 112 List<Object[]> cases = new ArrayList<>(Arrays.asList(new Object[][]{ 113 { 114 FunctionDescriptor.of(MemoryLayout.sequenceLayout(2, C_INT)), 115 NO_OPTIONS, 116 IS_LE ? "Unsupported layout: [2:i4]" : "Unsupported layout: [2:I4]" 117 }, 118 { 119 FunctionDescriptor.ofVoid(MemoryLayout.sequenceLayout(2, C_INT)), 120 NO_OPTIONS, 121 IS_LE ? "Unsupported layout: [2:i4]" : "Unsupported layout: [2:I4]" 122 }, 123 { 124 FunctionDescriptor.ofVoid(C_INT.withByteAlignment(2)), 125 NO_OPTIONS, 126 IS_LE ? "Unsupported layout: 2%i4" : "Unsupported layout: 2%I4" 127 }, 128 { 129 FunctionDescriptor.ofVoid(C_POINTER.withByteAlignment(2)), 130 NO_OPTIONS, 131 IS_LE ? "Unsupported layout: 2%a8" : "Unsupported layout: 2%A8" 132 }, 133 { 134 FunctionDescriptor.ofVoid(ValueLayout.JAVA_CHAR.withByteAlignment(4)), 135 NO_OPTIONS, 136 IS_LE ? "Unsupported layout: 4%c2" : "Unsupported layout: 4%C2" 137 }, 138 { 139 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 140 C_CHAR.withName("x").withByteAlignment(1), 141 C_SHORT.withName("y").withByteAlignment(1), 142 C_INT.withName("z").withByteAlignment(1) 143 ).withByteAlignment(1)), 144 NO_OPTIONS, 145 IS_LE ? "Unsupported layout: 1%s2" : "Unsupported layout: 1%S2" 146 }, 147 { 148 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 149 MemoryLayout.structLayout( 150 C_CHAR.withName("x").withByteAlignment(1), 151 C_SHORT.withName("y").withByteAlignment(1), 152 C_INT.withName("z").withByteAlignment(1) 153 ))), 154 NO_OPTIONS, 155 IS_LE ? "Unsupported layout: 1%s2" : "Unsupported layout: 1%S2" 156 }, 157 { 158 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 159 MemoryLayout.sequenceLayout( 160 C_INT.withByteAlignment(1) 161 ))), 162 NO_OPTIONS, 163 IS_LE ? "Unsupported layout: 1%i4" : "Unsupported layout: 1%I4" 164 }, 165 { 166 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 167 ValueLayout.JAVA_INT, 168 MemoryLayout.paddingLayout(4), // no excess padding 169 ValueLayout.JAVA_INT)), 170 NO_OPTIONS, 171 "unexpected offset" 172 }, 173 { 174 FunctionDescriptor.of(C_INT.withOrder(nonNativeOrder())), 175 NO_OPTIONS, 176 IS_LE ? "Unsupported layout: I4" : "Unsupported layout: i4" 177 }, 178 { 179 FunctionDescriptor.of(MemoryLayout.structLayout(C_INT.withOrder(nonNativeOrder()))), 180 NO_OPTIONS, 181 IS_LE ? "Unsupported layout: I4" : "Unsupported layout: i4" 182 }, 183 { 184 FunctionDescriptor.of(MemoryLayout.structLayout(MemoryLayout.sequenceLayout(C_INT.withOrder(nonNativeOrder())))), 185 NO_OPTIONS, 186 IS_LE ? "Unsupported layout: I4" : "Unsupported layout: i4" 187 }, 188 { 189 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 190 ValueLayout.JAVA_LONG, 191 ValueLayout.JAVA_INT)), // missing trailing padding 192 NO_OPTIONS, 193 "has unexpected size" 194 }, 195 { 196 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 197 ValueLayout.JAVA_INT, 198 MemoryLayout.paddingLayout(4))), // too much trailing padding 199 NO_OPTIONS, 200 "has unexpected size" 201 }, 202 })); 203 204 for (ValueLayout illegalLayout : List.of(C_CHAR, ValueLayout.JAVA_CHAR, C_BOOL, C_SHORT, C_FLOAT)) { 205 cases.add(new Object[]{ 206 FunctionDescriptor.ofVoid(C_INT, illegalLayout), 207 new Linker.Option[]{Linker.Option.firstVariadicArg(1)}, 208 "Invalid variadic argument layout" 209 }); 210 } 211 212 if (IS_SYSV) { 213 cases.add(new Object[] { 214 FunctionDescriptor.ofVoid(MemoryLayout.structLayout( 215 MemoryLayout.sequenceLayout( 216 C_INT 217 ))), 218 NO_OPTIONS, 219 "GroupLayout is too large" 220 }); 221 } 222 return cases.toArray(Object[][]::new); 223 } 224 225 private static ByteOrder nonNativeOrder() { 226 return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN 227 ? ByteOrder.BIG_ENDIAN 228 : ByteOrder.LITTLE_ENDIAN; 229 } 230 }