Skip to content

Commit 5fa61cc

Browse files
committed
[feat] Distinct kinds of NPE.
1 parent 2d82e28 commit 5fa61cc

File tree

4 files changed

+99
-7
lines changed

4 files changed

+99
-7
lines changed

lib/Core/ExecutionState.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ ExecutionState::~ExecutionState() {
163163
ExecutionState::ExecutionState(const ExecutionState &state)
164164
: initPC(state.initPC), pc(state.pc), prevPC(state.prevPC),
165165
stack(state.stack), stackBalance(state.stackBalance),
166-
incomingBBIndex(state.incomingBBIndex), depth(state.depth),
166+
incomingBBIndex(state.incomingBBIndex),
167+
lastBrConfidently(state.lastBrConfidently),
168+
outOfMemoryMarkers(state.outOfMemoryMarkers), depth(state.depth),
167169
level(state.level), addressSpace(state.addressSpace),
168170
constraints(state.constraints), eventsRecorder(state.eventsRecorder),
169171
targetForest(state.targetForest), pathOS(state.pathOS),

lib/Core/ExecutionState.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ class ExecutionState {
320320
/// @brief: TODO:
321321
bool lastBrConfidently = true;
322322

323+
/// @brief: TODO:
324+
ImmutableList<ref<Expr>> outOfMemoryMarkers;
325+
323326
/// @brief Exploration depth, i.e., number of times KLEE branched for this
324327
/// state
325328
std::uint32_t depth = 0;

lib/Core/Executor.cpp

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "klee/Solver/Common.h"
6363
#include "klee/Solver/Solver.h"
6464
#include "klee/Solver/SolverCmdLine.h"
65+
#include "klee/Solver/SolverUtil.h"
6566
#include "klee/Statistics/TimerStatIncrementer.h"
6667
#include "klee/Support/Casting.h"
6768
#include "klee/Support/ErrorHandling.h"
@@ -5424,6 +5425,7 @@ void Executor::executeAlloc(ExecutionState &state, ref<Expr> size, bool isLocal,
54245425
makeMockValue(state, "symCheckOutOfMemory", Expr::Bool);
54255426
address = SelectExpr::create(symCheckOutOfMemoryExpr,
54265427
Expr::createPointer(0), address);
5428+
state.outOfMemoryMarkers.push_back(symCheckOutOfMemoryExpr);
54275429
}
54285430

54295431
// state.addPointerResolution(address, mo);
@@ -6317,12 +6319,91 @@ void Executor::executeMemoryOperation(
63176319
StatePair branches =
63186320
forkInternal(estate, Expr::createIsZero(base), BranchType::MemOp);
63196321
ExecutionState *bound = branches.first;
6322+
63206323
if (bound) {
6321-
auto error = isReadFromSymbolicArray(uniqueBase)
6322-
? ReachWithError::MayBeNullPointerException
6323-
: ReachWithError::MustBeNullPointerException;
6324-
terminateStateOnTargetError(*bound, error);
6324+
// If there are no markers on `malloc` returning nullptr,
6325+
// then `confidence` depends on presence of `unbound` state.
6326+
if (!bound->outOfMemoryMarkers.empty()) {
6327+
// bound constraints already contain `Expr::createIsZero()`
6328+
std::vector<const Array *> markersArrays;
6329+
markersArrays.reserve(bound->outOfMemoryMarkers.size());
6330+
findSymbolicObjects(bound->outOfMemoryMarkers.begin(),
6331+
bound->outOfMemoryMarkers.end(), markersArrays);
6332+
6333+
// Do some iterations (2-3) to figure out if error is confident.
6334+
ref<Expr> allExcludedVectorsOfMarkers = Expr::createTrue();
6335+
6336+
bool convinced = false;
6337+
for (int tpCheckIteration = 0; tpCheckIteration < 2; ++tpCheckIteration) {
6338+
ref<SolverResponse> isConfidentResponse;
6339+
if (!solver->getResponse(bound->constraints.cs(),
6340+
allExcludedVectorsOfMarkers,
6341+
isConfidentResponse, bound->queryMetaData)) {
6342+
terminateStateOnSolverError(*bound, "Query timeout");
6343+
}
6344+
6345+
if (isa<ValidResponse>(isConfidentResponse)) {
6346+
reportStateOnTargetError(*bound,
6347+
ReachWithError::MustBeNullPointerException);
6348+
6349+
terminateStateOnProgramError(
6350+
*bound,
6351+
new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr,
6352+
"memory error: null pointer exception"),
6353+
StateTerminationConfidenceCategory::CONFIDENT);
6354+
convinced = true;
6355+
break;
6356+
}
6357+
6358+
// Receive current values of markers
6359+
std::vector<SparseStorage<unsigned char>> boundSetSolution;
6360+
isConfidentResponse->tryGetInitialValuesFor(markersArrays,
6361+
boundSetSolution);
6362+
Assignment nonConfidentResponseAssignment(markersArrays,
6363+
boundSetSolution);
6364+
6365+
// Exclude this combinations of markers
6366+
6367+
ref<Expr> conjExcludedVectorOfMarkers = Expr::createTrue();
6368+
for (ref<Expr> marker : bound->outOfMemoryMarkers) {
6369+
conjExcludedVectorOfMarkers = AndExpr::create(
6370+
conjExcludedVectorOfMarkers,
6371+
EqExpr::create(marker,
6372+
nonConfidentResponseAssignment.evaluate(marker)));
6373+
}
6374+
6375+
allExcludedVectorsOfMarkers =
6376+
OrExpr::create(allExcludedVectorsOfMarkers,
6377+
NotExpr::create(conjExcludedVectorOfMarkers));
6378+
}
6379+
6380+
if (!convinced) {
6381+
reportStateOnTargetError(*bound,
6382+
ReachWithError::MayBeNullPointerException);
6383+
6384+
terminateStateOnProgramError(
6385+
*bound,
6386+
new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr,
6387+
"memory error: null pointer exception"),
6388+
StateTerminationConfidenceCategory::PROBABLY);
6389+
}
6390+
6391+
} else {
6392+
auto error = branches.second != nullptr
6393+
? ReachWithError::MayBeNullPointerException
6394+
: ReachWithError::MustBeNullPointerException;
6395+
reportStateOnTargetError(*bound, error);
6396+
6397+
terminateStateOnProgramError(
6398+
*bound,
6399+
new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr,
6400+
"memory error: null pointer exception"),
6401+
branches.second != nullptr
6402+
? StateTerminationConfidenceCategory::PROBABLY
6403+
: StateTerminationConfidenceCategory::CONFIDENT);
6404+
}
63256405
}
6406+
63266407
if (!branches.second)
63276408
return;
63286409
ExecutionState *state = branches.second;
@@ -6916,7 +6997,8 @@ void Executor::executeMakeSymbolic(ExecutionState &state,
69166997
(!AllowSeedTruncation && obj->numBytes > mo->size))) {
69176998
std::stringstream msg;
69186999
msg << "replace size mismatch: " << mo->name << "[" << mo->size
6919-
<< "]" << " vs " << obj->name << "[" << obj->numBytes << "]"
7000+
<< "]"
7001+
<< " vs " << obj->name << "[" << obj->numBytes << "]"
69207002
<< " in test\n";
69217003

69227004
terminateStateOnUserError(state, msg.str());
@@ -7360,7 +7442,8 @@ void Executor::logState(const ExecutionState &state, int id,
73607442
*f << "Address memory object: " << object.first->address << "\n";
73617443
*f << "Memory object size: " << object.first->size << "\n";
73627444
}
7363-
*f << state.symbolics.size() << " symbolics total. " << "Symbolics:\n";
7445+
*f << state.symbolics.size() << " symbolics total. "
7446+
<< "Symbolics:\n";
73647447
size_t sc = 0;
73657448
for (const auto &symbolic : state.symbolics) {
73667449
*f << "Symbolic number " << sc++ << "\n";

lib/Expr/ExprUtil.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//===----------------------------------------------------------------------===//
99

1010
#include "klee/Expr/ExprUtil.h"
11+
#include "klee/ADT/ImmutableList.h"
1112
#include "klee/Expr/Expr.h"
1213
#include "klee/Expr/ExprHashMap.h"
1314
#include "klee/Expr/ExprVisitor.h"
@@ -176,6 +177,9 @@ template void klee::findSymbolicObjects<B>(B, B, std::vector<const Array *> &);
176177
typedef ExprHashSet::iterator C;
177178
template void klee::findSymbolicObjects<C>(C, C, std::vector<const Array *> &);
178179

180+
typedef ImmutableList<ref<Expr>>::iterator D;
181+
template void klee::findSymbolicObjects<D>(D, D, std::vector<const Array *> &);
182+
179183
typedef std::vector<ref<Expr>>::iterator A;
180184
template void klee::findObjects<A>(A, A, std::vector<const Array *> &);
181185

0 commit comments

Comments
 (0)