|
62 | 62 | #include "klee/Solver/Common.h"
|
63 | 63 | #include "klee/Solver/Solver.h"
|
64 | 64 | #include "klee/Solver/SolverCmdLine.h"
|
| 65 | +#include "klee/Solver/SolverUtil.h" |
65 | 66 | #include "klee/Statistics/TimerStatIncrementer.h"
|
66 | 67 | #include "klee/Support/Casting.h"
|
67 | 68 | #include "klee/Support/ErrorHandling.h"
|
@@ -5398,6 +5399,7 @@ void Executor::executeAlloc(ExecutionState &state, ref<Expr> size, bool isLocal,
|
5398 | 5399 | makeMockValue(state, "symCheckOutOfMemory", Expr::Bool);
|
5399 | 5400 | address = SelectExpr::create(symCheckOutOfMemoryExpr,
|
5400 | 5401 | Expr::createPointer(0), address);
|
| 5402 | + state.outOfMemoryMarkers.push_back(symCheckOutOfMemoryExpr); |
5401 | 5403 | }
|
5402 | 5404 |
|
5403 | 5405 | // state.addPointerResolution(address, mo);
|
@@ -6267,12 +6269,91 @@ void Executor::executeMemoryOperation(
|
6267 | 6269 | StatePair branches =
|
6268 | 6270 | forkInternal(estate, Expr::createIsZero(base), BranchType::MemOp);
|
6269 | 6271 | ExecutionState *bound = branches.first;
|
| 6272 | + |
6270 | 6273 | if (bound) {
|
6271 |
| - auto error = isReadFromSymbolicArray(uniqueBase) |
6272 |
| - ? ReachWithError::MayBeNullPointerException |
6273 |
| - : ReachWithError::MustBeNullPointerException; |
6274 |
| - terminateStateOnTargetError(*bound, error); |
| 6274 | + // If there are no markers on `malloc` returning nullptr, |
| 6275 | + // then `confidence` depends on presence of `unbound` state. |
| 6276 | + if (!bound->outOfMemoryMarkers.empty()) { |
| 6277 | + // bound constraints already contain `Expr::createIsZero()` |
| 6278 | + std::vector<const Array *> markersArrays; |
| 6279 | + markersArrays.reserve(bound->outOfMemoryMarkers.size()); |
| 6280 | + findSymbolicObjects(bound->outOfMemoryMarkers.begin(), |
| 6281 | + bound->outOfMemoryMarkers.end(), markersArrays); |
| 6282 | + |
| 6283 | + // Do some iterations (2-3) to figure out if error is confident. |
| 6284 | + ref<Expr> allExcludedVectorsOfMarkers = Expr::createTrue(); |
| 6285 | + |
| 6286 | + bool convinced = false; |
| 6287 | + for (int tpCheckIteration = 0; tpCheckIteration < 2; ++tpCheckIteration) { |
| 6288 | + ref<SolverResponse> isConfidentResponse; |
| 6289 | + if (!solver->getResponse(bound->constraints.cs(), |
| 6290 | + allExcludedVectorsOfMarkers, |
| 6291 | + isConfidentResponse, bound->queryMetaData)) { |
| 6292 | + terminateStateOnSolverError(*bound, "Query timeout"); |
| 6293 | + } |
| 6294 | + |
| 6295 | + if (isa<ValidResponse>(isConfidentResponse)) { |
| 6296 | + reportStateOnTargetError(*bound, |
| 6297 | + ReachWithError::MustBeNullPointerException); |
| 6298 | + |
| 6299 | + terminateStateOnProgramError( |
| 6300 | + *bound, |
| 6301 | + new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr, |
| 6302 | + "memory error: null pointer exception"), |
| 6303 | + StateTerminationConfidenceCategory::CONFIDENT); |
| 6304 | + convinced = true; |
| 6305 | + break; |
| 6306 | + } |
| 6307 | + |
| 6308 | + // Receive current values of markers |
| 6309 | + std::vector<SparseStorage<unsigned char>> boundSetSolution; |
| 6310 | + isConfidentResponse->tryGetInitialValuesFor(markersArrays, |
| 6311 | + boundSetSolution); |
| 6312 | + Assignment nonConfidentResponseAssignment(markersArrays, |
| 6313 | + boundSetSolution); |
| 6314 | + |
| 6315 | + // Exclude this combinations of markers |
| 6316 | + |
| 6317 | + ref<Expr> conjExcludedVectorOfMarkers = Expr::createTrue(); |
| 6318 | + for (ref<Expr> marker : bound->outOfMemoryMarkers) { |
| 6319 | + conjExcludedVectorOfMarkers = AndExpr::create( |
| 6320 | + conjExcludedVectorOfMarkers, |
| 6321 | + EqExpr::create(marker, |
| 6322 | + nonConfidentResponseAssignment.evaluate(marker))); |
| 6323 | + } |
| 6324 | + |
| 6325 | + allExcludedVectorsOfMarkers = |
| 6326 | + OrExpr::create(allExcludedVectorsOfMarkers, |
| 6327 | + NotExpr::create(conjExcludedVectorOfMarkers)); |
| 6328 | + } |
| 6329 | + |
| 6330 | + if (!convinced) { |
| 6331 | + reportStateOnTargetError(*bound, |
| 6332 | + ReachWithError::MayBeNullPointerException); |
| 6333 | + |
| 6334 | + terminateStateOnProgramError( |
| 6335 | + *bound, |
| 6336 | + new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr, |
| 6337 | + "memory error: null pointer exception"), |
| 6338 | + StateTerminationConfidenceCategory::PROBABLY); |
| 6339 | + } |
| 6340 | + |
| 6341 | + } else { |
| 6342 | + auto error = branches.second != nullptr |
| 6343 | + ? ReachWithError::MayBeNullPointerException |
| 6344 | + : ReachWithError::MustBeNullPointerException; |
| 6345 | + reportStateOnTargetError(*bound, error); |
| 6346 | + |
| 6347 | + terminateStateOnProgramError( |
| 6348 | + *bound, |
| 6349 | + new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr, |
| 6350 | + "memory error: null pointer exception"), |
| 6351 | + branches.second != nullptr |
| 6352 | + ? StateTerminationConfidenceCategory::PROBABLY |
| 6353 | + : StateTerminationConfidenceCategory::CONFIDENT); |
| 6354 | + } |
6275 | 6355 | }
|
| 6356 | + |
6276 | 6357 | if (!branches.second)
|
6277 | 6358 | return;
|
6278 | 6359 | ExecutionState *state = branches.second;
|
|
0 commit comments