1 // Copyright 2021 Code Intelligence GmbH 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.code_intelligence.jazzer.autofuzz; 16 17 import static com.code_intelligence.jazzer.autofuzz.TestHelpers.autofuzzTestCase; 18 import static com.code_intelligence.jazzer.autofuzz.TestHelpers.consumeTestCase; 19 import static org.junit.Assert.assertEquals; 20 21 import com.code_intelligence.jazzer.api.CannedFuzzedDataProvider; 22 import com.code_intelligence.jazzer.api.FuzzedDataProvider; 23 import com.google.json.JsonSanitizer; 24 import java.io.ByteArrayInputStream; 25 import java.lang.reflect.Type; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.Map; 29 import org.junit.Test; 30 31 public class MetaTest { 32 public enum TestEnum { 33 FOO, 34 BAR, 35 BAZ, 36 } 37 38 @Test testConsume()39 public void testConsume() throws NoSuchMethodException { 40 consumeTestCase(5, "5", Collections.singletonList(5)); 41 consumeTestCase((short) 5, "(short) 5", Collections.singletonList((short) 5)); 42 consumeTestCase(5L, "5L", Collections.singletonList(5L)); 43 consumeTestCase(5.0F, "5.0F", Collections.singletonList(5.0F)); 44 consumeTestCase('\n', "'\\n'", Collections.singletonList('\n')); 45 consumeTestCase('\'', "'\\''", Collections.singletonList('\'')); 46 consumeTestCase('\\', "'\\\\'", Collections.singletonList('\\')); 47 48 String testString = "foo\n\t\\\"bar"; 49 // The expected string is obtained from testString by escaping and wrapping into escaped quotes. 50 consumeTestCase(testString, "\"foo\\n\\t\\\\\\\"bar\"", 51 Arrays.asList((byte) 1, // do not return null 52 testString.length(), testString)); 53 54 consumeTestCase(null, "null", Collections.singletonList((byte) 0)); 55 56 boolean[] testBooleans = new boolean[] {true, false, true}; 57 consumeTestCase(testBooleans, "new boolean[]{true, false, true}", 58 Arrays.asList((byte) 1, // do not return null for the array 59 2 * 3, testBooleans)); 60 61 char[] testChars = new char[] {'a', '\n', '\''}; 62 consumeTestCase(testChars, "new char[]{'a', '\\n', '\\''}", 63 Arrays.asList((byte) 1, // do not return null for the array 64 2 * 3 * Character.BYTES + Character.BYTES, testChars[0], 2 * 3 * Character.BYTES, 65 2 * 3 * Character.BYTES, // remaining bytes, 2 times what is needed for 3 chars 66 testChars[1], testChars[2])); 67 68 char[] testNoChars = new char[] {}; 69 consumeTestCase(testNoChars, "new char[]{}", 70 Arrays.asList((byte) 1, // do not return null for the array 71 0, 'a', 0, 0)); 72 73 short[] testShorts = new short[] {(short) 1, (short) 2, (short) 3}; 74 consumeTestCase(testShorts, "new short[]{(short) 1, (short) 2, (short) 3}", 75 Arrays.asList((byte) 1, // do not return null for the array 76 2 * 3 * Short.BYTES, // remaining bytes 77 testShorts)); 78 79 long[] testLongs = new long[] {1L, 2L, 3L}; 80 consumeTestCase(testLongs, "new long[]{1L, 2L, 3L}", 81 Arrays.asList((byte) 1, // do not return null for the array 82 2 * 3 * Long.BYTES, // remaining bytes 83 testLongs)); 84 85 consumeTestCase(new String[] {"foo", "bar", "foo\nbar"}, 86 "new java.lang.String[]{\"foo\", \"bar\", \"foo\\nbar\"}", 87 Arrays.asList((byte) 1, // do not return null for the array 88 32, // remaining bytes 89 (byte) 1, // do not return null for the string 90 31, // remaining bytes 91 "foo", 92 28, // remaining bytes 93 28, // array length 94 (byte) 1, // do not return null for the string 95 27, // remaining bytes 96 "bar", 97 (byte) 1, // do not return null for the string 98 23, // remaining bytes 99 "foo\nbar")); 100 101 byte[] testInputStreamBytes = new byte[] {(byte) 1, (byte) 2, (byte) 3}; 102 consumeTestCase(new ByteArrayInputStream(testInputStreamBytes), 103 "new java.io.ByteArrayInputStream(new byte[]{(byte) 1, (byte) 2, (byte) 3})", 104 Arrays.asList((byte) 1, // do not return null for the InputStream 105 2 * 3, // remaining bytes (twice the desired length) 106 testInputStreamBytes)); 107 108 consumeTestCase(TestEnum.BAR, 109 String.format("%s.%s", TestEnum.class.getName(), TestEnum.BAR.name()), 110 Arrays.asList((byte) 1, // do not return null for the enum value 111 1 /* second value */ 112 )); 113 114 consumeTestCase(YourAverageJavaClass.class, 115 "com.code_intelligence.jazzer.autofuzz.YourAverageJavaClass.class", 116 Collections.singletonList((byte) 1)); 117 118 Type stringStringMapType = 119 MetaTest.class.getDeclaredMethod("returnsStringStringMap").getGenericReturnType(); 120 Map<String, String> expectedMap = 121 java.util.stream.Stream 122 .of(new java.util.AbstractMap.SimpleEntry<>("key0", "value0"), 123 new java.util.AbstractMap.SimpleEntry<>("key1", "value1"), 124 new java.util.AbstractMap.SimpleEntry<>("key2", (java.lang.String) null)) 125 .collect(java.util.HashMap::new, 126 (map, e) -> map.put(e.getKey(), e.getValue()), java.util.HashMap::putAll); 127 consumeTestCase(stringStringMapType, expectedMap, 128 "java.util.stream.Stream.<java.util.AbstractMap.SimpleEntry<java.lang.String, java.lang.String>>of(new java.util.AbstractMap.SimpleEntry<>(\"key0\", \"value0\"), new java.util.AbstractMap.SimpleEntry<>(\"key1\", \"value1\"), new java.util.AbstractMap.SimpleEntry<>(\"key2\", (java.lang.String) null)).collect(java.util.HashMap::new, (map, e) -> map.put(e.getKey(), e.getValue()), java.util.HashMap::putAll)", 129 Arrays.asList((byte) 1, // do not return null for the map 130 32, // remaining bytes 131 (byte) 1, // do not return null for the string 132 31, // remaining bytes 133 "key0", 134 (byte) 1, // do not return null for the string 135 28, // remaining bytes 136 "value0", 137 28, // remaining bytes 138 28, // consumeArrayLength 139 (byte) 1, // do not return null for the string 140 27, // remaining bytes 141 "key1", 142 (byte) 1, // do not return null for the string 143 23, // remaining bytes 144 "value1", 145 (byte) 1, // do not return null for the string 146 27, // remaining bytes 147 "key2", 148 (byte) 0 // *do* return null for the string 149 )); 150 } 151 returnsStringStringMap()152 private Map<String, String> returnsStringStringMap() { 153 throw new IllegalStateException( 154 "Should not be called, only exists to construct its generic return type"); 155 } 156 isFive(int arg)157 public static boolean isFive(int arg) { 158 return arg == 5; 159 } 160 intEquals(int arg1, int arg2)161 public static boolean intEquals(int arg1, int arg2) { 162 return arg1 == arg2; 163 } 164 165 @Test testAutofuzz()166 public void testAutofuzz() throws NoSuchMethodException { 167 autofuzzTestCase(true, "com.code_intelligence.jazzer.autofuzz.MetaTest.isFive(5)", 168 MetaTest.class.getMethod("isFive", int.class), Collections.singletonList(5)); 169 autofuzzTestCase(false, "com.code_intelligence.jazzer.autofuzz.MetaTest.intEquals(5, 4)", 170 MetaTest.class.getMethod("intEquals", int.class, int.class), Arrays.asList(5, 4)); 171 autofuzzTestCase("foobar", "(\"foo\").concat(\"bar\")", 172 String.class.getMethod("concat", String.class), 173 Arrays.asList((byte) 1, 6, "foo", (byte) 1, 6, "bar")); 174 autofuzzTestCase("jazzer", "new java.lang.String(\"jazzer\")", 175 String.class.getConstructor(String.class), Arrays.asList((byte) 1, 12, "jazzer")); 176 autofuzzTestCase("\"jazzer\"", "com.google.json.JsonSanitizer.sanitize(\"jazzer\")", 177 JsonSanitizer.class.getMethod("sanitize", String.class), 178 Arrays.asList((byte) 1, 12, "jazzer")); 179 180 FuzzedDataProvider data = 181 CannedFuzzedDataProvider.create(Arrays.asList((byte) 1, // do not return null 182 8, // remainingBytes 183 "buzz")); 184 assertEquals("fizzbuzz", new Meta(null).autofuzz(data, "fizz" ::concat)); 185 } 186 187 // Regression test for https://github.com/CodeIntelligenceTesting/jazzer/issues/465. 188 @Test testPrivateInterface()189 public void testPrivateInterface() { 190 autofuzzTestCase(null, 191 "com.code_intelligence.jazzer.autofuzz.OpinionatedClass.doStuffWithPrivateInterface(((java.util.function.Supplier<com.code_intelligence.jazzer.autofuzz.OpinionatedClass.PublicImplementation>) (() -> {com.code_intelligence.jazzer.autofuzz.OpinionatedClass.PublicImplementation autofuzzVariable0 = new com.code_intelligence.jazzer.autofuzz.OpinionatedClass.PublicImplementation(); return autofuzzVariable0;})).get())", 192 OpinionatedClass.class.getDeclaredMethods()[0], 193 Arrays.asList((byte) 1, // do not return null 194 0, // first (and only) class on the classpath 195 (byte) 1, // do not return null 196 0 /* first (and only) constructor*/)); 197 } 198 returnsClassArray()199 Class<?>[] returnsClassArray() { 200 throw new IllegalStateException( 201 "Should not be called, only exists to construct its generic return type"); 202 } 203 204 @Test testGetRawType()205 public void testGetRawType() throws NoSuchMethodException { 206 Type classArrayType = 207 MetaTest.class.getDeclaredMethod("returnsClassArray").getGenericReturnType(); 208 assertEquals(Class[].class, Meta.getRawType(classArrayType)); 209 } 210 } 211 212 class OpinionatedClass { doStuffWithPrivateInterface( @uppressWarnings"unused") PrivateInterface thing)213 public static void doStuffWithPrivateInterface( 214 @SuppressWarnings("unused") PrivateInterface thing) {} 215 216 private interface PrivateInterface {} 217 218 public static class PublicImplementation implements PrivateInterface {} 219 } 220