diff options
Diffstat (limited to 'src/main/java/com/code_intelligence/jazzer/mutation/combinator/ProductMutator.java')
-rw-r--r-- | src/main/java/com/code_intelligence/jazzer/mutation/combinator/ProductMutator.java | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/main/java/com/code_intelligence/jazzer/mutation/combinator/ProductMutator.java b/src/main/java/com/code_intelligence/jazzer/mutation/combinator/ProductMutator.java new file mode 100644 index 00000000..9057fd35 --- /dev/null +++ b/src/main/java/com/code_intelligence/jazzer/mutation/combinator/ProductMutator.java @@ -0,0 +1,138 @@ +/* + * Copyright 2023 Code Intelligence GmbH + * + * 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. + */ + +package com.code_intelligence.jazzer.mutation.combinator; + +import static com.code_intelligence.jazzer.mutation.support.InputStreamSupport.extendWithZeros; +import static com.code_intelligence.jazzer.mutation.support.Preconditions.require; +import static com.code_intelligence.jazzer.mutation.support.Preconditions.requireNonNullElements; +import static java.util.Arrays.stream; +import static java.util.stream.Collectors.joining; + +import com.code_intelligence.jazzer.mutation.api.Debuggable; +import com.code_intelligence.jazzer.mutation.api.PseudoRandom; +import com.code_intelligence.jazzer.mutation.api.SerializingInPlaceMutator; +import com.code_intelligence.jazzer.mutation.api.SerializingMutator; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.function.Predicate; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public final class ProductMutator extends SerializingInPlaceMutator<Object[]> { + // Inverse frequency in which product type mutators should be used in cross over. + private final static int INVERSE_PICK_VALUE_SUPPLIER_FREQUENCY = 100; + + private final SerializingMutator[] mutators; + + ProductMutator(SerializingMutator[] mutators) { + requireNonNullElements(mutators); + require(mutators.length > 0, "mutators must not be empty"); + this.mutators = Arrays.copyOf(mutators, mutators.length); + } + + @Override + public Object[] read(DataInputStream in) throws IOException { + Object[] value = new Object[mutators.length]; + for (int i = 0; i < mutators.length; i++) { + value[i] = mutators[i].read(in); + } + return value; + } + + @Override + public Object[] readExclusive(InputStream in) throws IOException { + Object[] value = new Object[mutators.length]; + int lastIndex = mutators.length - 1; + DataInputStream endlessData = new DataInputStream(extendWithZeros(in)); + for (int i = 0; i < lastIndex; i++) { + value[i] = mutators[i].read(endlessData); + } + value[lastIndex] = mutators[lastIndex].readExclusive(in); + return value; + } + + @Override + public void write(Object[] value, DataOutputStream out) throws IOException { + for (int i = 0; i < mutators.length; i++) { + mutators[i].write(value[i], out); + } + } + + @Override + public void writeExclusive(Object[] value, OutputStream out) throws IOException { + DataOutputStream dataOut = new DataOutputStream(out); + int lastIndex = mutators.length - 1; + for (int i = 0; i < lastIndex; i++) { + mutators[i].write(value[i], dataOut); + } + mutators[lastIndex].writeExclusive(value[lastIndex], out); + } + + @Override + protected Object[] makeDefaultInstance() { + return new Object[mutators.length]; + } + + @Override + public void initInPlace(Object[] reference, PseudoRandom prng) { + for (int i = 0; i < mutators.length; i++) { + reference[i] = mutators[i].init(prng); + } + } + + @Override + public void mutateInPlace(Object[] reference, PseudoRandom prng) { + int i = prng.indexIn(mutators); + reference[i] = mutators[i].mutate(reference[i], prng); + } + + @Override + public void crossOverInPlace(Object[] reference, Object[] otherReference, PseudoRandom prng) { + for (int i = 0; i < mutators.length; i++) { + SerializingMutator mutator = mutators[i]; + Object value = reference[i]; + Object otherValue = otherReference[i]; + Object crossedOver = prng.pickValue(value, otherValue, + () -> mutator.crossOver(value, otherValue, prng), INVERSE_PICK_VALUE_SUPPLIER_FREQUENCY); + if (crossedOver == otherReference) { + // If otherReference was picked, it needs to be detached as mutating + // it is prohibited in cross over. + crossedOver = mutator.detach(crossedOver); + } + reference[i] = crossedOver; + } + } + + @Override + public Object[] detach(Object[] value) { + Object[] clone = new Object[mutators.length]; + for (int i = 0; i < mutators.length; i++) { + clone[i] = mutators[i].detach(value[i]); + } + return clone; + } + + @Override + public String toDebugString(Predicate<Debuggable> isInCycle) { + return stream(mutators) + .map(mutator -> mutator.toDebugString(isInCycle)) + .collect(joining(", ", "[", "]")); + } +} |