forked from sqlancer/sqlancer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStatementReducer.java
More file actions
126 lines (103 loc) · 4.75 KB
/
Copy pathStatementReducer.java
File metadata and controls
126 lines (103 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package sqlancer;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import sqlancer.common.query.Query;
public class StatementReducer<G extends GlobalState<O, ?, C>, O extends DBMSSpecificOptions<?>, C extends SQLancerDBConnection>
implements Reducer<G> {
private final DatabaseProvider<G, O, C> provider;
private boolean observedChange;
private int partitionNum;
public StatementReducer(DatabaseProvider<G, O, C> provider) {
this.provider = provider;
}
private boolean hasNotReachedLimit(long curr, long limit) {
if (limit == MainOptions.NO_REDUCE_LIMIT) {
return true;
}
return curr < limit;
}
@SuppressWarnings("unchecked")
@Override
public void reduce(G state, Reproducer<G> reproducer, G newGlobalState) throws Exception {
long maxReduceTime = state.getOptions().getMaxStatementReduceTime();
long maxReduceSteps = state.getOptions().getMaxStatementReduceSteps();
List<Query<C>> knownToReproduceBugStatements = new ArrayList<>();
for (Query<?> stat : state.getState().getStatements()) {
knownToReproduceBugStatements.add((Query<C>) stat);
}
System.out.println("Starting query:");
printQueries(knownToReproduceBugStatements);
System.out.println();
if (knownToReproduceBugStatements.size() <= 1) {
return;
}
Instant timeOfReductionBegins = Instant.now();
long currentReduceSteps = 0;
long currentReduceTime = 0;
partitionNum = 2;
while (knownToReproduceBugStatements.size() >= 2 && hasNotReachedLimit(currentReduceSteps, maxReduceSteps)
&& hasNotReachedLimit(currentReduceTime, maxReduceTime)) {
observedChange = false;
knownToReproduceBugStatements = tryReduction(state, reproducer, newGlobalState,
knownToReproduceBugStatements);
if (!observedChange) {
if (partitionNum == knownToReproduceBugStatements.size()) {
break;
}
// increase the search granularity
partitionNum = Math.min(partitionNum * 2, knownToReproduceBugStatements.size());
currentReduceSteps++;
Instant currentInstant = Instant.now();
currentReduceTime = Duration.between(currentInstant, timeOfReductionBegins).getSeconds();
}
}
System.out.println("Reduced query:");
printQueries(knownToReproduceBugStatements);
newGlobalState.getState().setStatements(new ArrayList<>(knownToReproduceBugStatements));
}
private List<Query<C>> tryReduction(G state, // NOPMD
Reproducer<G> reproducer, G newGlobalState, List<Query<C>> knownToReproduceBugStatements) throws Exception {
List<Query<C>> statements = knownToReproduceBugStatements;
int start = 0;
int subLength = statements.size() / partitionNum;
while (start < statements.size()) {
// newStatements = candidate[:start] + candidate[start+subLength:]
// in other word, remove [start, start+subLength) from candidates
try (C con2 = provider.createDatabase(newGlobalState)) {
newGlobalState.setConnection(con2);
List<Query<C>> candidateStatements = new ArrayList<>(statements);
candidateStatements.subList(start, start + subLength).clear();
newGlobalState.getState().setStatements(new ArrayList<>(candidateStatements));
for (Query<C> s : candidateStatements) {
try {
s.execute(newGlobalState);
} catch (Throwable ignoredException) {
// ignore
}
}
try {
if (reproducer.bugStillTriggers(newGlobalState)) {
observedChange = true;
statements = candidateStatements;
partitionNum = Math.max(partitionNum - 1, 2);
break;
// reproducer.outputHook((SQLite3GlobalState) newGlobalState);
// state.getLogger().logReduced(newGlobalState.getState());
}
} catch (Throwable ignoredException) {
}
}
start = start + subLength;
}
return statements;
}
private void printQueries(List<Query<C>> statements) {
System.out.println("===============================");
for (Query<?> q : statements) {
System.out.println(q.getLogString());
}
System.out.println("===============================");
}
}