ReadTreeFuzzer.java
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.node.ObjectNode;
import tools.jackson.databind.node.ArrayNode;
import tools.jackson.databind.node.JsonNodeFactory;
import java.util.*;
import java.math.BigInteger;
import java.math.BigDecimal;
import java.lang.IllegalArgumentException;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.core.JacksonException;
public class ReadTreeFuzzer {
public static void fuzzerTestOneInput(FuzzedDataProvider data) {
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode root = mapper.readTree(data.consumeString(500000));
if (root == null) return;
// Test various JsonNode operations
int numOperations = data.consumeInt(1, 20);
for (int i = 0; i < numOperations && data.remainingBytes() > 10; i++) {
int operation = data.consumeInt(0, 25);
switch(operation) {
case 0:
// get by field name
String fieldName = data.consumeString(100);
JsonNode child = root.get(fieldName);
if (child != null) {
child.asText();
child.isNull();
child.isValueNode();
}
break;
case 1:
// get by index
int idx = data.consumeInt();
root.get(idx);
break;
case 2:
// path operations
String path = data.consumeString(200);
JsonNode pathNode = root.path(path);
pathNode.isMissingNode();
break;
case 3:
// at (JsonPointer)
String pointer = data.consumeString(200);
root.at(pointer);
break;
case 4:
// type checks
root.isArray();
root.isObject();
root.isTextual();
root.isNumber();
root.isBoolean();
root.isBinary();
root.isPojo();
root.isIntegralNumber();
root.isFloatingPointNumber();
root.isBigDecimal();
root.isBigInteger();
break;
case 5:
// value extraction
root.asText();
root.asText("default");
break;
case 6:
root.asInt();
root.asInt(0);
break;
case 7:
root.asLong();
root.asLong(0L);
break;
case 8:
root.asDouble();
root.asDouble(0.0);
break;
case 9:
root.asBoolean();
root.asBoolean(false);
break;
case 10:
// tree traversal - Jackson 3.x uses values() and properties()
root.values();
root.properties();
root.iterator();
break;
case 11:
// has operations
String checkField = data.consumeString(100);
root.has(checkField);
root.has(data.consumeInt());
root.hasNonNull(checkField);
break;
case 12:
// size
root.size();
root.isEmpty();
break;
case 13:
// find operations
String findField = data.consumeString(100);
root.findValue(findField);
root.findPath(findField);
root.findValues(findField);
root.findValuesAsString(findField);
root.findParent(findField);
root.findParents(findField);
break;
case 14:
// withObject operations (for ObjectNode)
if (root.isObject()) {
try {
String withField = data.consumeString(100);
root.withObject(withField);
} catch (UnsupportedOperationException e) {}
}
break;
case 15:
// withArray (for ObjectNode)
if (root.isObject()) {
try {
String arrayField = data.consumeString(100);
root.withArray(arrayField);
} catch (UnsupportedOperationException e) {}
}
break;
case 16:
// equals
String json2 = data.consumeString(10000);
try {
JsonNode other = mapper.readTree(json2);
root.equals(other);
} catch (JacksonException e) {}
break;
case 17:
// treeToValue
int classIdx = data.consumeInt(0, classes.length - 1);
mapper.treeToValue(root, classes[classIdx]);
break;
case 18:
// write operations
mapper.writeValueAsString(root);
break;
case 19:
mapper.writeValueAsBytes(root);
break;
case 20:
// deepCopy
root.deepCopy();
break;
case 21:
// number operations if applicable
if (root.isNumber()) {
root.numberValue();
root.canConvertToInt();
root.canConvertToLong();
root.canConvertToExactIntegral();
}
break;
case 22:
// binary operations if applicable
if (root.isBinary()) {
root.binaryValue();
}
break;
case 23:
// textValue
root.textValue();
break;
case 24:
// pretty print
root.toPrettyString();
break;
case 25:
// require operations
try {
root.require();
root.requireNonNull();
} catch (IllegalArgumentException e) {}
break;
}
}
} catch (JacksonException | IllegalArgumentException e) { }
}
public static Class[] classes = { DummyClass.class, Integer.class, String.class, Byte.class, List.class, Map.class,
TreeMap.class, BitSet.class, TimeZone.class, Date.class, Calendar.class, Locale.class };
public static class DummyClass {
public TreeMap<String, Integer> _treeMap;
public List<String> _arrayList;
public Set<String> _hashSet;
public Map<String, Object> _hashMap;
public List<Integer> _asList = Arrays.asList(1, 2, 3);
public int[] _intArray;
public long[] _longArray;
public short[] _shortArray;
public float[] _floatArray;
public double[] _doubleArray;
public byte[] _byteArray;
public char[] _charArray;
public String[] _stringArray;
public BitSet _bitSet;
public Date _date;
public TimeZone _timeZone;
public Calendar _calendar;
public Locale _locale;
public Integer[] _integerArray;
public boolean _boolean;
public char _char;
public byte _byte;
public short _short;
public int _int;
public float _float;
}
}