Skip to content

Commit 37f71ec

Browse files
committed
[feat] Handling of NPE moved to separate function.
1 parent ae3c89e commit 37f71ec

File tree

2 files changed

+104
-103
lines changed

2 files changed

+104
-103
lines changed

lib/Core/Executor.cpp

+101-103
Original file line numberDiff line numberDiff line change
@@ -5471,6 +5471,100 @@ void Executor::executeFree(ExecutionState &state, ref<Expr> address,
54715471
}
54725472
}
54735473

5474+
ExecutionState *Executor::handleNullPointerException(ExecutionState &state,
5475+
ref<Expr> base) {
5476+
StatePair branches =
5477+
forkInternal(state, Expr::createIsZero(base), BranchType::MemOp);
5478+
ExecutionState *bound = branches.first;
5479+
if (!bound) {
5480+
return branches.second;
5481+
}
5482+
5483+
// If there are no markers on `malloc` returning nullptr,
5484+
// then `confidence` depends on presence of `unbound` state.
5485+
if (!bound->outOfMemoryMarkers.empty()) {
5486+
// bound constraints already contain `Expr::createIsZero()`
5487+
std::vector<const Array *> markersArrays;
5488+
markersArrays.reserve(bound->outOfMemoryMarkers.size());
5489+
findSymbolicObjects(bound->outOfMemoryMarkers.begin(),
5490+
bound->outOfMemoryMarkers.end(), markersArrays);
5491+
5492+
// Do some iterations (2-3) to figure out if error is confident.
5493+
ref<Expr> allExcludedVectorsOfMarkers = Expr::createTrue();
5494+
5495+
bool convinced = false;
5496+
for (int tpCheckIteration = 0; tpCheckIteration < 2; ++tpCheckIteration) {
5497+
ref<SolverResponse> isConfidentResponse;
5498+
if (!solver->getResponse(bound->constraints.cs(),
5499+
allExcludedVectorsOfMarkers, isConfidentResponse,
5500+
bound->queryMetaData)) {
5501+
terminateStateOnSolverError(*bound, "Query timeout");
5502+
}
5503+
5504+
if (isa<ValidResponse>(isConfidentResponse)) {
5505+
reportStateOnTargetError(*bound,
5506+
ReachWithError::MustBeNullPointerException);
5507+
5508+
terminateStateOnProgramError(
5509+
*bound,
5510+
new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr,
5511+
"memory error: null pointer exception"),
5512+
StateTerminationConfidenceCategory::CONFIDENT);
5513+
convinced = true;
5514+
break;
5515+
}
5516+
5517+
// Receive current values of markers
5518+
std::vector<SparseStorage<unsigned char>> boundSetSolution;
5519+
isConfidentResponse->tryGetInitialValuesFor(markersArrays,
5520+
boundSetSolution);
5521+
Assignment nonConfidentResponseAssignment(markersArrays,
5522+
boundSetSolution);
5523+
5524+
// Exclude this combinations of markers
5525+
5526+
ref<Expr> conjExcludedVectorOfMarkers = Expr::createTrue();
5527+
for (ref<Expr> marker : bound->outOfMemoryMarkers) {
5528+
conjExcludedVectorOfMarkers = AndExpr::create(
5529+
conjExcludedVectorOfMarkers,
5530+
EqExpr::create(marker,
5531+
nonConfidentResponseAssignment.evaluate(marker)));
5532+
}
5533+
5534+
allExcludedVectorsOfMarkers =
5535+
OrExpr::create(allExcludedVectorsOfMarkers,
5536+
NotExpr::create(conjExcludedVectorOfMarkers));
5537+
}
5538+
5539+
if (!convinced) {
5540+
reportStateOnTargetError(*bound,
5541+
ReachWithError::MayBeNullPointerException);
5542+
5543+
terminateStateOnProgramError(
5544+
*bound,
5545+
new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr,
5546+
"memory error: null pointer exception"),
5547+
StateTerminationConfidenceCategory::PROBABLY);
5548+
}
5549+
5550+
} else {
5551+
auto error = branches.second != nullptr
5552+
? ReachWithError::MayBeNullPointerException
5553+
: ReachWithError::MustBeNullPointerException;
5554+
reportStateOnTargetError(*bound, error);
5555+
5556+
terminateStateOnProgramError(
5557+
*bound,
5558+
new ErrorEvent(locationOf(*bound), StateTerminationType::Ptr,
5559+
"memory error: null pointer exception"),
5560+
branches.second != nullptr
5561+
? StateTerminationConfidenceCategory::PROBABLY
5562+
: StateTerminationConfidenceCategory::CONFIDENT);
5563+
}
5564+
5565+
return branches.second;
5566+
}
5567+
54745568
bool Executor::resolveExact(ExecutionState &estate, ref<Expr> address,
54755569
KType *type, ExactResolutionList &results,
54765570
const std::string &name) {
@@ -5496,20 +5590,12 @@ bool Executor::resolveExact(ExecutionState &estate, ref<Expr> address,
54965590
Simplificator::simplifyExpr(estate.constraints.cs(), base).simplified;
54975591
uniqueBase = toUnique(estate, uniqueBase);
54985592

5499-
StatePair branches =
5500-
forkInternal(estate, Expr::createIsZero(base), BranchType::MemOp);
5501-
ExecutionState *bound = branches.first;
5502-
if (bound) {
5503-
auto error = isReadFromSymbolicArray(uniqueBase)
5504-
? ReachWithError::MayBeNullPointerException
5505-
: ReachWithError::MustBeNullPointerException;
5506-
terminateStateOnTargetError(*bound, error);
5507-
}
5508-
if (!branches.second) {
5509-
address = Expr::createPointer(0);
5593+
ExecutionState *handledNPEState = handleNullPointerException(estate, base);
5594+
if (!handledNPEState) {
5595+
return false;
55105596
}
55115597

5512-
ExecutionState &state = *branches.second;
5598+
ExecutionState &state = *handledNPEState;
55135599

55145600
ResolutionList rl;
55155601
bool mayBeOutOfBound = true;
@@ -6266,97 +6352,9 @@ void Executor::executeMemoryOperation(
62666352

62676353
ref<Expr> uniqueBase = toUnique(estate, base);
62686354

6269-
StatePair branches =
6270-
forkInternal(estate, Expr::createIsZero(base), BranchType::MemOp);
6271-
ExecutionState *bound = branches.first;
6272-
6273-
if (bound) {
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-
}
6355-
}
6356-
6357-
if (!branches.second)
6355+
ExecutionState *state = handleNullPointerException(estate, base);
6356+
if (!state)
63586357
return;
6359-
ExecutionState *state = branches.second;
63606358

63616359
// fast path: single in-bounds resolution
63626360
IDType idFastResult;
@@ -6542,7 +6540,7 @@ void Executor::executeMemoryOperation(
65426540
maxNewWriteableOSSize =
65436541
std::max(maxNewWriteableOSSize, wos->getSparseStorageEntries());
65446542
if (wos->readOnly) {
6545-
branches =
6543+
StatePair branches =
65466544
forkInternal(*state, Expr::createIsZero(unboundConditions[i]),
65476545
BranchType::MemOp);
65486546
assert(branches.first);

lib/Core/Executor.h

+3
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,9 @@ class Executor : public Interpreter {
413413
const std::vector<Assignment> &resolveConcretizations,
414414
std::vector<ref<Expr>> &results);
415415

416+
ExecutionState *handleNullPointerException(ExecutionState &state,
417+
ref<Expr> base);
418+
416419
// do address resolution / object binding / out of bounds checking
417420
// and perform the operation
418421
void executeMemoryOperation(ExecutionState &state, bool isWrite,

0 commit comments

Comments
 (0)