clang: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

20#include "llvm/ADT/FoldingSet.h"

21#include "llvm/ADT/ImmutableSet.h"

22#include "llvm/ADT/STLExtras.h"

23#include "llvm/ADT/SmallSet.h"

24#include "llvm/ADT/StringExtras.h"

25#include "llvm/Support/Compiler.h"

26#include "llvm/Support/raw_ostream.h"

27#include

28#include

29#include

30

31using namespace clang;

32using namespace ento;

33

34

35

37 static_assert(BO_LT < BO_GT && BO_GT < BO_LE && BO_LE < BO_GE &&

38 BO_GE < BO_EQ && BO_EQ < BO_NE,

39 "This class relies on operators order. Rework it otherwise.");

40

41public:

46 };

47

48private:

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 static constexpr size_t CmpOpCount = BO_NE - BO_LT + 1;

77 const TriStateKind CmpOpTable[CmpOpCount][CmpOpCount + 1] = {

78

85 };

86

88 return static_cast<size_t>(OP - BO_LT);

89 }

90

91public:

92 constexpr size_t getCmpOpCount() const { return CmpOpCount; }

93

96 }

97

100 return CmpOpTable[getIndexFromOp(CurrentOP)][getIndexFromOp(QueriedOP)];

101 }

102

104 return CmpOpTable[getIndexFromOp(CurrentOP)][CmpOpCount];

105 }

106};

107

108

109

110

111

112RangeSet::ContainerType RangeSet::Factory::EmptySet{};

113

115 ContainerType Result;

118 std::back_inserter(Result));

119 return makePersistent(std::move(Result));

120}

121

123 ContainerType Result;

124 Result.reserve(Original.size() + 1);

125

126 const_iterator Lower = llvm::lower_bound(Original, Element);

127 Result.insert(Result.end(), Original.begin(), Lower);

128 Result.push_back(Element);

129 Result.insert(Result.end(), Lower, Original.end());

130

131 return makePersistent(std::move(Result));

132}

133

135 return add(Original, Range(Point));

136}

137

139 ContainerType Result = unite(*LHS.Impl, *RHS.Impl);

140 return makePersistent(std::move(Result));

141}

142

144 ContainerType Result;

147 return makePersistent(std::move(Result));

148}

149

151 return unite(Original, Range(ValueFactory.getValue(Point)));

152}

153

155 llvm::APSInt To) {

156 return unite(Original,

157 Range(ValueFactory.getValue(From), ValueFactory.getValue(To)));

158}

159

160template

162 std::swap(First, Second);

163 std::swap(FirstEnd, SecondEnd);

164}

165

167 const ContainerType &RHS) {

168 if (LHS.empty())

169 return RHS;

170 if (RHS.empty())

171 return LHS;

172

173 using llvm::APSInt;

174 using iterator = ContainerType::const_iterator;

175

176 iterator First = LHS.begin();

177 iterator FirstEnd = LHS.end();

178 iterator Second = RHS.begin();

179 iterator SecondEnd = RHS.end();

182

183

184

185

186

187 if (Min == First->From() && Min == Second->From()) {

188 if (First->To() > Second->To()) {

189

190

191

192

193

194

195 if (++Second == SecondEnd)

196

197

198

199

200 return LHS;

201 } else {

202

203

204

205

206

207

208

209 if (++First == FirstEnd)

210

211

212

213

214 return RHS;

215 }

216 }

217

219 ContainerType Result;

220

221

222

223

224 const auto AppendTheRest = [&Result](iterator I, iterator E) {

227 };

228

229 while (true) {

230

231

232

233 if (First->From() > Second->From())

235

236

237

238

239

240

241 const llvm::APSInt &UnionStart = First->From();

242

243

244 while (true) {

245

246

247

248 while (First->To() >= Second->To()) {

249

250 if (++Second == SecondEnd) {

251

252

253

254

255

256 Result.emplace_back(UnionStart, First->To());

257

258

259

260 return AppendTheRest(++First, FirstEnd);

261 }

262 }

263

264

265

266

267

268

269 if (First->To() < Second->From() - One)

270 break;

271

272

273

274

275

276

277 if (++First == FirstEnd) {

278

279

280

281

282

283 Result.emplace_back(UnionStart, Second->To());

284

285

286

287 return AppendTheRest(++Second, SecondEnd);

288 }

289

290

291

292

293

294

295

297 }

298

299

300

301

302

303

304

305 Result.emplace_back(UnionStart, First->To());

306

307

308 if (++First == FirstEnd)

309

310

311

312 return AppendTheRest(Second, SecondEnd);

313 }

314

315 llvm_unreachable("Normally, we should not reach here");

316}

317

319 ContainerType Result;

320 Result.push_back(From);

321 return makePersistent(std::move(Result));

322}

323

324RangeSet RangeSet::Factory::makePersistent(ContainerType &&From) {

325 llvm::FoldingSetNodeID ID;

326 void *InsertPos;

327

328 From.Profile(ID);

329 ContainerType *Result = Cache.FindNodeOrInsertPos(ID, InsertPos);

330

332

333

334

335 Result = construct(std::move(From));

337 }

338

340}

341

342RangeSet::ContainerType *RangeSet::Factory::construct(ContainerType &&From) {

343 void *Buffer = Arena.Allocate();

344 return new (Buffer) ContainerType(std::move(From));

345}

346

349 return begin()->From();

350}

351

354 return std::prev(end())->To();

355}

356

359 return begin()->From().isUnsigned();

360}

361

364 return begin()->From().getBitWidth();

365}

366

370}

371

372bool RangeSet::containsImpl(llvm::APSInt &Point) const {

373 if (isEmpty() || !pin(Point))

374 return false;

375

376 Range Dummy(Point);

378 if (It == begin())

379 return false;

380

381 return std::prev(It)->Includes(Point);

382}

383

384bool RangeSet::pin(llvm::APSInt &Point) const {

387 return false;

388

389 Type.apply(Point);

390 return true;

391}

392

393bool RangeSet::pin(llvm::APSInt &Lower, llvm::APSInt &Upper) const {

394

395

396

397

398

402

403 switch (LowerTest) {

405 switch (UpperTest) {

407

408

409 if (Lower <= Upper)

410 return false;

411

412

413 Lower = Type.getMinValue();

414 Upper = Type.getMaxValue();

415 break;

417

418 Lower = Type.getMinValue();

419 Type.apply(Upper);

420 break;

422

423 Lower = Type.getMinValue();

424 Upper = Type.getMaxValue();

425 break;

426 }

427 break;

429 switch (UpperTest) {

431

432 Type.apply(Lower);

433 Upper = Type.getMaxValue();

434 break;

436

437 Type.apply(Lower);

438 Type.apply(Upper);

439 break;

441

442 Type.apply(Lower);

443 Upper = Type.getMaxValue();

444 break;

445 }

446 break;

448 switch (UpperTest) {

450

451 return false;

453

454 Lower = Type.getMinValue();

455 Type.apply(Upper);

456 break;

458

459

460 if (Lower <= Upper)

461 return false;

462

463

464 Lower = Type.getMinValue();

465 Upper = Type.getMaxValue();

466 break;

467 }

468 break;

469 }

470

471 return true;

472}

473

475 llvm::APSInt Upper) {

476 if (What.isEmpty() || !What.pin(Lower, Upper))

477 return getEmptySet();

478

479 ContainerType DummyContainer;

480

481 if (Lower <= Upper) {

482

483

484

485

486

487

488

489

490

491

493 return getEmptySet();

494

495 DummyContainer.push_back(

496 Range(ValueFactory.getValue(Lower), ValueFactory.getValue(Upper)));

497 } else {

498

499

500

501

502

503

504

506 return getEmptySet();

507

508 DummyContainer.push_back(

509 Range(ValueFactory.getMinValue(Upper), ValueFactory.getValue(Upper)));

510 DummyContainer.push_back(

511 Range(ValueFactory.getValue(Lower), ValueFactory.getMaxValue(Lower)));

512 }

513

514 return intersect(*What.Impl, DummyContainer);

515}

516

518 const RangeSet::ContainerType &RHS) {

519 ContainerType Result;

520 Result.reserve(std::max(LHS.size(), RHS.size()));

521

523 FirstEnd = LHS.end(), SecondEnd = RHS.end();

524

525

526

527

528 while (First != FirstEnd && Second != SecondEnd) {

529

530

531

532

533 if (Second->From() < First->From())

535

536

537 do {

538

539

540

541

542

543

544 if (Second->From() > First->To()) {

545

546

547

548

550 break;

551 }

552

553

554

555

556

557

558

559

560 const llvm::APSInt &IntersectionStart = Second->From();

561

562

563

564

565 if (Second->To() > First->To()) {

566

567

569 }

570

571

572

573

574

575

576

577

578

579

580

581

582 Result.push_back(Range(IntersectionStart, Second->To()));

583 ++Second;

584

585

586 } while (Second != SecondEnd);

587 }

588

590 return getEmptySet();

591

592 return makePersistent(std::move(Result));

593}

594

596

599 return getEmptySet();

600

601 return intersect(*LHS.Impl, *RHS.Impl);

602}

603

605 if (LHS.containsImpl(Point))

606 return getRangeSet(ValueFactory.getValue(Point));

607

608 return getEmptySet();

609}

610

613 return getEmptySet();

614

615 const llvm::APSInt SampleValue = What.getMinValue();

616 const llvm::APSInt &MIN = ValueFactory.getMinValue(SampleValue);

617 const llvm::APSInt &MAX = ValueFactory.getMaxValue(SampleValue);

618

619 ContainerType Result;

620 Result.reserve(What.size() + (SampleValue == MIN));

621

622

625

626 const llvm::APSInt &From = It->From();

627 const llvm::APSInt &To = It->To();

628

629 if (From == MIN) {

630

631 if (To == MAX) {

632 return What;

633 }

634

636

637

638

639 if (Last->To() == MAX) {

640

641

642

643 Result.emplace_back(MIN, ValueFactory.getValue(-Last->From()));

644

646 } else {

647

648 Result.emplace_back(MIN, MIN);

649 }

650

651

652 if (To != MIN) {

653 Result.emplace_back(ValueFactory.getValue(-To), MAX);

654 }

655

656

657 ++It;

658 }

659

660

661 for (; It != End; ++It) {

662

663 const llvm::APSInt &NewFrom = ValueFactory.getValue(-It->To());

664 const llvm::APSInt &NewTo = ValueFactory.getValue(-It->From());

665

666

667 Result.emplace_back(NewFrom, NewTo);

668 }

669

671 return makePersistent(std::move(Result));

672}

673

674

675

677

679 return What;

680

684

685 if (IsTruncation)

686 return makePersistent(truncateTo(What, Ty));

687

688

689

690

691

692

693

694

695

696

697

698

699

700 if (IsConversion && (!IsPromotion || !What.isUnsigned()))

701 return makePersistent(convertTo(What, Ty));

702

703 assert(IsPromotion && "Only promotion operation from unsigneds left.");

704 return makePersistent(promoteTo(What, Ty));

705}

706

710}

711

712RangeSet::ContainerType RangeSet::Factory::truncateTo(RangeSet What,

714 using llvm::APInt;

715 using llvm::APSInt;

716 ContainerType Result;

717 ContainerType Dummy;

718

719

720

721

722

723

724

725 uint64_t CastRangeSize = APInt::getMaxValue(Ty.getBitWidth()).getZExtValue();

726 for (const Range &R : What) {

727

728 APSInt FromInt = R.From();

729 APSInt ToInt = R.To();

730

731

732 uint64_t CurrentRangeSize = (ToInt - FromInt).getZExtValue();

733

734

735 Dummy.clear();

736 if (CurrentRangeSize >= CastRangeSize) {

737 Dummy.emplace_back(ValueFactory.getMinValue(Ty),

738 ValueFactory.getMaxValue(Ty));

739 Result = std::move(Dummy);

740 break;

741 }

742

743 Ty.apply(FromInt);

745 const APSInt &PersistentFrom = ValueFactory.getValue(FromInt);

746 const APSInt &PersistentTo = ValueFactory.getValue(ToInt);

747 if (FromInt > ToInt) {

748 Dummy.emplace_back(ValueFactory.getMinValue(Ty), PersistentTo);

749 Dummy.emplace_back(PersistentFrom, ValueFactory.getMaxValue(Ty));

750 } else

751 Dummy.emplace_back(PersistentFrom, PersistentTo);

752

753

755 }

756

758}

759

760

761

762

763

764

765

766

767

768

769

770

771

772

773

774

775

776

777

778RangeSet::ContainerType RangeSet::Factory::convertTo(RangeSet What,

780 using llvm::APInt;

781 using llvm::APSInt;

782 using Bounds = std::pair<const APSInt &, const APSInt &>;

783 ContainerType AscendArray;

784 ContainerType DescendArray;

785 auto CastRange = [Ty, &VF = ValueFactory](const Range &R) -> Bounds {

786

787 APSInt FromInt = R.From();

788 APSInt ToInt = R.To();

789

790 Ty.apply(FromInt);

792 return {VF.getValue(FromInt), VF.getValue(ToInt)};

793 };

794

796 const auto *It = What.begin();

797 const auto *E = What.end();

798 while (It != E) {

799 Bounds NewBounds = CastRange(*(It++));

800

801 if (NewBounds.first < LastConvertedInt) {

802 DescendArray.emplace_back(NewBounds.first, NewBounds.second);

803 break;

804 }

805

806

807

808

809 if (NewBounds.first > NewBounds.second) {

810 DescendArray.emplace_back(ValueFactory.getMinValue(Ty), NewBounds.second);

811 AscendArray.emplace_back(NewBounds.first, ValueFactory.getMaxValue(Ty));

812 } else

813

814 AscendArray.emplace_back(NewBounds.first, NewBounds.second);

815 LastConvertedInt = NewBounds.first;

816 }

817

818 while (It != E) {

819 Bounds NewBounds = CastRange(*(It++));

820 DescendArray.emplace_back(NewBounds.first, NewBounds.second);

821 }

822

823 return unite(AscendArray, DescendArray);

824}

825

826

827RangeSet::ContainerType RangeSet::Factory::promoteTo(RangeSet What,

829 ContainerType Result;

830

832

833

834

835

836 for (const Range &R : What) {

837

838 llvm::APSInt FromInt = R.From();

839 llvm::APSInt ToInt = R.To();

840

841 Ty.apply(FromInt);

843 Result.emplace_back(ValueFactory.getValue(FromInt),

844 ValueFactory.getValue(ToInt));

845 }

847}

848

850 const llvm::APSInt &Point) {

852 return From;

853

854 llvm::APSInt Upper = Point;

855 llvm::APSInt Lower = Point;

856

857 ++Upper;

858 --Lower;

859

860

861 return intersect(From, Upper, Lower);

862}

863

865 OS << '[' << toString(From(), 10) << ", " << toString(To(), 10) << ']';

866}

868

870 OS << "{ ";

871 llvm::interleaveComma(*this, OS, [&OS](const Range &R) { R.dump(OS); });

872 OS << " }";

873}

875

877

878namespace {

879class EquivalenceClass;

880}

881

885

888

889namespace {

890

891

892

893

894

895

896

897

898

899

900

901

902

903

904

905

906

907

908

909

910

911

912

913

914class EquivalenceClass : public llvm::FoldingSetNode {

915public:

916

917 [[nodiscard]] static inline EquivalenceClass find(ProgramStateRef State,

919

920

925

928

929

931

932

933

934

935

936

937

938

939

940

941

942

944

945

946 [[nodiscard]] inline bool isTriviallyDead(ProgramStateRef State,

948

954 EquivalenceClass First, EquivalenceClass Second);

957 EquivalenceClass Other) const;

958 [[nodiscard]] static inline ClassSet getDisequalClasses(ProgramStateRef State,

960 [[nodiscard]] inline ClassSet getDisequalClasses(ProgramStateRef State) const;

961 [[nodiscard]] inline ClassSet

962 getDisequalClasses(DisequalityMapTy Map, ClassSet::Factory &Factory) const;

963

964 [[nodiscard]] static inline std::optional

966 EquivalenceClass Second);

967 [[nodiscard]] static inline std::optional

969

970

973

974

978 EquivalenceClass Class);

979

980 void dumpToStream(ProgramStateRef State, raw_ostream &os) const;

982 dumpToStream(State, llvm::errs());

983 }

984

985

986 [[nodiscard]] LLVM_ATTRIBUTE_UNUSED static bool

988

989 [[nodiscard]] QualType getType() const {

990 return getRepresentativeSymbol()->getType();

991 }

992

993 EquivalenceClass() = delete;

994 EquivalenceClass(const EquivalenceClass &) = default;

995 EquivalenceClass &operator=(const EquivalenceClass &) = delete;

996 EquivalenceClass(EquivalenceClass &&) = default;

997 EquivalenceClass &operator=(EquivalenceClass &&) = delete;

998

1001 }

1005 }

1006

1007 static void Profile(llvm::FoldingSetNodeID &ID, uintptr_t CID) {

1008 ID.AddInteger(CID);

1009 }

1010

1011 void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, this->ID); }

1012

1013private:

1014 EquivalenceClass(SymbolRef Sym)

1015 : ID(reinterpret_cast<uintptr_t>(Sym)) {}

1016

1017

1018

1019

1020

1021

1022 SymbolRef getRepresentativeSymbol() const {

1024 }

1025 static inline SymbolSet::Factory &getMembersFactory(ProgramStateRef State);

1026

1030

1031 static inline bool

1032 addToDisequalityInfo(DisequalityMapTy &Info, ConstraintRangeTy &Constraints,

1034 EquivalenceClass First, EquivalenceClass Second);

1035

1036

1038};

1039

1040

1041

1042

1043

1044[[nodiscard]] LLVM_ATTRIBUTE_UNUSED bool

1045areFeasible(ConstraintRangeTy Constraints) {

1046 return llvm::none_of(

1047 Constraints,

1048 [](const std::pair<EquivalenceClass, RangeSet> &ClassConstraint) {

1049 return ClassConstraint.second.isEmpty();

1050 });

1051}

1052

1054 EquivalenceClass Class) {

1055 return State->get(Class);

1056}

1057

1060 return getConstraint(State, EquivalenceClass::find(State, Sym));

1061}

1062

1064 EquivalenceClass Class,

1066 return State->set(Class, Constraint);

1067}

1068

1070 ConstraintRangeTy Constraints) {

1071 return State->set(Constraints);

1072}

1073

1074

1075

1076

1077

1078

1079

1080

1081

1082

1083

1084

1085

1086

1087std::optional meansEquality(const SymSymExpr *Sym) {

1089 case BO_Sub:

1090

1091 return false;

1092 case BO_EQ:

1093

1094 return true;

1095 case BO_NE:

1096

1097 return false;

1098 default:

1099 return std::nullopt;

1100 }

1101}

1102

1103

1104

1105

1106

1107template <class SecondTy, class... RestTy>

1109 SecondTy Second, RestTy... Tail);

1110

1111template <class... RangeTy> struct IntersectionTraits;

1112

1113template <class... TailTy> struct IntersectionTraits<RangeSet, TailTy...> {

1114

1116};

1117

1118template <> struct IntersectionTraits<> {

1119

1120

1121 using Type = std::optional;

1122};

1123

1124template <class OptionalOrPointer, class... TailTy>

1125struct IntersectionTraits<OptionalOrPointer, TailTy...> {

1126

1127 using Type = typename IntersectionTraits<TailTy...>::Type;

1128};

1129

1130template

1131[[nodiscard]] inline EndTy intersect(RangeSet::Factory &F, EndTy End) {

1132

1133

1134 return End;

1135}

1136

1137[[nodiscard]] LLVM_ATTRIBUTE_UNUSED inline std::optional

1139

1140

1141 if (End) {

1142 return *End;

1143 }

1144 return std::nullopt;

1145}

1146

1147template <class... RestTy>

1149 RangeSet Second, RestTy... Tail) {

1150

1151

1152 return intersect(F, F.intersect(Head, Second), Tail...);

1153}

1154

1155template <class SecondTy, class... RestTy>

1157 SecondTy Second, RestTy... Tail) {

1158 if (Second) {

1159

1160 return intersect(F, Head, *Second, Tail...);

1161 }

1162

1163

1164 return intersect(F, Head, Tail...);

1165}

1166

1167

1168

1169

1170

1171

1172

1173

1174

1175

1176

1177

1178

1179

1180

1181

1182

1183

1184

1185

1186

1187

1188template <class HeadTy, class SecondTy, class... RestTy>

1189[[nodiscard]] inline

1190 typename IntersectionTraits<HeadTy, SecondTy, RestTy...>::Type

1192 RestTy... Tail) {

1193 if (Head) {

1194 return intersect(F, *Head, Second, Tail...);

1195 }

1196 return intersect(F, Second, Tail...);

1197}

1198

1199

1200

1201

1202

1203

1204

1205

1206

1207

1208class SymbolicRangeInferrer

1209 : public SymExprVisitor<SymbolicRangeInferrer, RangeSet> {

1210public:

1211 template

1213 SourceType Origin) {

1214 SymbolicRangeInferrer Inferrer(F, State);

1215 return Inferrer.infer(Origin);

1216 }

1217

1219 if (std::optional RS = getRangeForNegatedSym(Sym))

1220 return *RS;

1221

1222

1223

1224

1225 return infer(Sym->getType());

1226 }

1227

1229 if (std::optional RS = getRangeForNegatedUnarySym(USE))

1230 return *RS;

1231 return infer(USE->getType());

1232 }

1233

1235 return VisitBinaryOperator(Sym);

1236 }

1237

1239 return VisitBinaryOperator(Sym);

1240 }

1241

1243 return intersect(

1244 RangeFactory,

1245

1246

1247

1248

1249

1250

1251 getRangeForNegatedSymSym(SSE),

1252

1253 getRangeCommutativeSymSym(SSE),

1254

1255

1256

1257 getRangeForComparisonSymbol(SSE),

1258

1259

1260 getRangeForEqualities(SSE),

1261

1262 VisitBinaryOperator(SSE));

1263 }

1264

1265private:

1267 : ValueFactory(F.getValueFactory()), RangeFactory(F), State(S) {}

1268

1269

1270

1271

1272

1274 return {RangeFactory, Val};

1275 }

1276

1277

1280

1283 return infer(Sym);

1284 }

1285

1286

1287 return infer(DestType);

1288 }

1289

1291 return intersect(RangeFactory,

1292

1293

1294 getConstraint(State, Sym),

1295

1296

1297 Visit(Sym));

1298 }

1299

1300 RangeSet infer(EquivalenceClass Class) {

1301 if (const RangeSet *AssociatedConstraint = getConstraint(State, Class))

1302 return *AssociatedConstraint;

1303

1304 return infer(Class.getType());

1305 }

1306

1307

1309

1310

1311 RangeSet Result(RangeFactory, ValueFactory.getMinValue(T),

1312 ValueFactory.getMaxValue(T));

1313

1314

1316 return assumeNonZero(Result, T);

1317

1318 return Result;

1319 }

1320

1321 template

1322 RangeSet VisitBinaryOperator(const BinarySymExprTy *Sym) {

1323

1324

1325

1326

1327

1328

1329

1330

1331

1332

1333

1334 QualType ResultType = Sym->getType();

1335 return VisitBinaryOperator(inferAs(Sym->getLHS(), ResultType),

1336 Sym->getOpcode(),

1337 inferAs(Sym->getRHS(), ResultType), ResultType);

1338 }

1339

1342

1343

1344

1345

1346

1347

1348

1349

1350

1351

1353 assert(!Origin.isEmpty());

1355 }

1356

1357

1358

1359

1360 std::optional convert(const Range &Origin, APSIntType To) {

1363 return std::nullopt;

1364 }

1365 return Range(ValueFactory.Convert(To, Origin.From()),

1366 ValueFactory.Convert(To, Origin.To()));

1367 }

1368

1369 template <BinaryOperator::Opcode Op>

1372

1373 Range CoarseLHS = fillGaps(LHS);

1374 Range CoarseRHS = fillGaps(RHS);

1375

1376 APSIntType ResultType = ValueFactory.getAPSIntType(T);

1377

1378

1379

1380 auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);

1381 auto ConvertedCoarseRHS = convert(CoarseRHS, ResultType);

1382

1383

1384

1385 if (!ConvertedCoarseLHS || !ConvertedCoarseRHS) {

1386 return infer(T);

1387 }

1388

1389 return VisitBinaryOperator(*ConvertedCoarseLHS, *ConvertedCoarseRHS, T);

1390 }

1391

1392 template <BinaryOperator::Opcode Op>

1394 return infer(T);

1395 }

1396

1397

1398

1399

1400

1401

1402

1403

1404

1406 APSIntType RangeType = ValueFactory.getAPSIntType(T);

1407

1409 return Range(ValueFactory.getMinValue(RangeType), Origin.To());

1410 }

1411

1412 if (Origin.From().isMinSignedValue()) {

1413

1414

1415

1416 return {ValueFactory.getMinValue(RangeType),

1417 ValueFactory.getMaxValue(RangeType)};

1418 }

1419

1420

1421

1422

1423

1424

1425

1426

1427

1428

1429

1430

1431 llvm::APSInt AbsMax = std::max(-Origin.From(), Origin.To());

1432

1433

1434 return {ValueFactory.getValue(-AbsMax), ValueFactory.getValue(AbsMax)};

1435 }

1436

1437

1439 APSIntType IntType = ValueFactory.getAPSIntType(T);

1441 }

1442

1443 template

1444 std::optional getRangeForNegatedExpr(ProduceNegatedSymFunc F,

1446

1449 return std::nullopt;

1450

1452 if (const RangeSet *NegatedRange = getConstraint(State, NegatedSym))

1453 return RangeFactory.negate(*NegatedRange);

1454

1455 return std::nullopt;

1456 }

1457

1458 std::optional getRangeForNegatedUnarySym(const UnarySymExpr *USE) {

1459

1460

1461 return getRangeForNegatedExpr(

1463 if (USE->getOpcode() == UO_Minus)

1465 return nullptr;

1466 },

1468 }

1469

1470 std::optional getRangeForNegatedSymSym(const SymSymExpr *SSE) {

1471 return getRangeForNegatedExpr(

1472 [SSE, State = this->State]() -> SymbolRef {

1474 return State->getSymbolManager().acquire<SymSymExpr>(

1476 return nullptr;

1477 },

1479 }

1480

1481 std::optional getRangeForNegatedSym(SymbolRef Sym) {

1482 return getRangeForNegatedExpr(

1483 [Sym, State = this->State]() {

1484 return State->getSymbolManager().acquire(

1485 Sym, UO_Minus, Sym->getType());

1486 },

1488 }

1489

1490 std::optional getRangeCommutativeSymSym(const SymSymExpr *SSE) {

1492 bool IsCommutative = llvm::is_contained(

1493

1494 {BO_EQ, BO_NE, BO_Or, BO_And, BO_Add, BO_Mul, BO_Xor}, Op);

1495 if (!IsCommutative)

1496 return std::nullopt;

1497

1500 if (const RangeSet *Range = getConstraint(State, Commuted))

1502 return std::nullopt;

1503 }

1504

1505

1506

1507

1508

1509

1510

1511

1512

1513

1514

1515 std::optional getRangeForComparisonSymbol(const SymSymExpr *SSE) {

1517

1518

1520 return std::nullopt;

1521

1523

1527

1528 SymbolManager &SymMgr = State->getSymbolManager();

1529

1530

1531

1532

1533

1534

1536

1537

1538

1539 for (size_t i = 0; i < CmpOpTable.getCmpOpCount(); ++i) {

1540

1541

1545 const RangeSet *QueriedRangeSet = getConstraint(State, SymSym);

1546

1547

1548

1549 if (!QueriedRangeSet) {

1553 QueriedRangeSet = getConstraint(State, SymSym);

1554 }

1555

1556 if (!QueriedRangeSet || QueriedRangeSet->isEmpty())

1557 continue;

1558

1559 const llvm::APSInt *ConcreteValue = QueriedRangeSet->getConcreteValue();

1560 const bool isInFalseBranch =

1561 ConcreteValue ? (*ConcreteValue == 0) : false;

1562

1563

1564

1565

1566 if (isInFalseBranch)

1568

1570 CmpOpTable.getCmpOpState(CurrentOP, QueriedOP);

1571

1573 if (LastQueriedOpToUnknown != CurrentOP &&

1574 LastQueriedOpToUnknown != QueriedOP) {

1575

1576

1577

1578

1579

1580 BranchState = CmpOpTable.getCmpOpStateForUnknownX2(CurrentOP);

1581 } else {

1582 LastQueriedOpToUnknown = QueriedOP;

1583 continue;

1584 }

1585 }

1586

1588 : getFalseRange(T);

1589 }

1590

1591 return std::nullopt;

1592 }

1593

1594 std::optional getRangeForEqualities(const SymSymExpr *Sym) {

1595 std::optional Equality = meansEquality(Sym);

1596

1597 if (!Equality)

1598 return std::nullopt;

1599

1600 if (std::optional AreEqual =

1601 EquivalenceClass::areEqual(State, Sym->getLHS(), Sym->getRHS())) {

1602

1603

1604

1605 if (*AreEqual == *Equality) {

1606 return getTrueRange(Sym->getType());

1607 }

1608

1609 return getFalseRange(Sym->getType());

1610 }

1611

1612 return std::nullopt;

1613 }

1614

1617 return assumeNonZero(TypeRange, T);

1618 }

1619

1621 const llvm::APSInt &Zero = ValueFactory.getValue(0, T);

1622 return RangeSet(RangeFactory, Zero);

1623 }

1624

1628};

1629

1630

1631

1632

1633

1634template <>

1635RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_NE>(RangeSet LHS,

1639

1641 if (intersect(RangeFactory, LHS, RHS).isEmpty())

1642 return getTrueRange(T);

1643

1644 } else {

1645

1646

1647

1648

1649

1650

1651

1652

1653

1654

1655

1656

1661 return getTrueRange(T);

1662

1666 return getTrueRange(T);

1667 }

1668 }

1669

1670

1673

1674 RangeSet CastedLHS = RangeFactory.castTo(LHS, CastingType);

1675 RangeSet CastedRHS = RangeFactory.castTo(RHS, CastingType);

1676

1677 if (intersect(RangeFactory, CastedLHS, CastedRHS).isEmpty())

1678 return getTrueRange(T);

1679 }

1680

1681

1682 return infer(T);

1683}

1684

1685template <>

1686RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Or>(Range LHS, Range RHS,

1688 APSIntType ResultType = ValueFactory.getAPSIntType(T);

1690

1691 bool IsLHSPositiveOrZero = LHS.From() >= Zero;

1692 bool IsRHSPositiveOrZero = RHS.From() >= Zero;

1693

1694 bool IsLHSNegative = LHS.To() < Zero;

1695 bool IsRHSNegative = RHS.To() < Zero;

1696

1697

1698 if ((IsLHSPositiveOrZero && IsRHSPositiveOrZero) ||

1699 (IsLHSNegative && IsRHSNegative)) {

1700

1701 const llvm::APSInt &Min = std::max(LHS.From(), RHS.From());

1702

1703

1704

1705

1706

1707

1708

1709

1710

1711

1712

1713

1714 const llvm::APSInt &Max = IsLHSNegative

1715 ? ValueFactory.getValue(--Zero)

1716 : ValueFactory.getMaxValue(ResultType);

1717

1718 return {RangeFactory, ValueFactory.getValue(Min), Max};

1719 }

1720

1721

1722 if (IsLHSNegative || IsRHSNegative) {

1723

1724 return {RangeFactory, ValueFactory.getMinValue(ResultType),

1725 ValueFactory.getValue(--Zero)};

1726 }

1727

1728 RangeSet DefaultRange = infer(T);

1729

1730

1731

1732

1733

1735 return assumeNonZero(DefaultRange, T);

1736 }

1737

1738

1739 return DefaultRange;

1740}

1741

1742template <>

1743RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_And>(Range LHS,

1746 APSIntType ResultType = ValueFactory.getAPSIntType(T);

1748

1749 bool IsLHSPositiveOrZero = LHS.From() >= Zero;

1750 bool IsRHSPositiveOrZero = RHS.From() >= Zero;

1751

1752 bool IsLHSNegative = LHS.To() < Zero;

1753 bool IsRHSNegative = RHS.To() < Zero;

1754

1755

1756 if ((IsLHSPositiveOrZero && IsRHSPositiveOrZero) ||

1757 (IsLHSNegative && IsRHSNegative)) {

1758

1759 const llvm::APSInt &Max = std::min(LHS.To(), RHS.To());

1760

1761

1762

1763 const llvm::APSInt &Min = IsLHSNegative

1764 ? ValueFactory.getMinValue(ResultType)

1765 : ValueFactory.getValue(Zero);

1766

1767 return {RangeFactory, Min, Max};

1768 }

1769

1770

1771 if (IsLHSPositiveOrZero || IsRHSPositiveOrZero) {

1772

1773

1774

1775

1776 const llvm::APSInt &Max = IsLHSPositiveOrZero ? LHS.To() : RHS.To();

1777

1778

1779

1780 return {RangeFactory, ValueFactory.getValue(Zero),

1781 ValueFactory.getValue(Max)};

1782 }

1783

1784

1785 return infer(T);

1786}

1787

1788template <>

1789RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Rem>(Range LHS,

1792 llvm::APSInt Zero = ValueFactory.getAPSIntType(T).getZeroValue();

1793

1794 Range ConservativeRange = getSymmetricalRange(RHS, T);

1795

1796 llvm::APSInt Max = ConservativeRange.To();

1797 llvm::APSInt Min = ConservativeRange.From();

1798

1799 if (Max == Zero) {

1800

1801

1802

1803 return RangeFactory.getEmptySet();

1804 }

1805

1806

1807

1808

1809

1810

1811

1812

1813

1814

1815

1816 if (Min.isSigned()) {

1818 }

1820

1821 bool IsLHSPositiveOrZero = LHS.From() >= Zero;

1822 bool IsRHSPositiveOrZero = RHS.From() >= Zero;

1823

1824

1825

1826 if (IsLHSPositiveOrZero && IsRHSPositiveOrZero) {

1827

1828

1829 Max = std::min(LHS.To(), Max);

1830

1831

1832

1833

1834

1835

1836

1838 }

1839

1840

1841

1842 return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};

1843}

1844

1845RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,

1848

1849

1851 return RangeFactory.getEmptySet();

1852 }

1853

1854 switch (Op) {

1855 case BO_NE:

1856 return VisitBinaryOperator<BO_NE>(LHS, RHS, T);

1857 case BO_Or:

1858 return VisitBinaryOperator<BO_Or>(LHS, RHS, T);

1859 case BO_And:

1860 return VisitBinaryOperator<BO_And>(LHS, RHS, T);

1861 case BO_Rem:

1862 return VisitBinaryOperator<BO_Rem>(LHS, RHS, T);

1863 default:

1864 return infer(T);

1865 }

1866}

1867

1868

1869

1870

1871

1873public:

1876

1877

1878

1879

1880

1883

1884

1885

1886 return S1->get() == S2->get() &&

1887 S1->get() == S2->get();

1888 }

1889

1890 bool canReasonAbout(SVal X) const override;

1891

1893

1896

1899

1902

1905

1906 void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n",

1907 unsigned int Space = 0, bool IsDot = false) const override;

1908 void printValue(raw_ostream &Out, ProgramStateRef State,

1910 void printConstraints(raw_ostream &Out, ProgramStateRef State,

1911 const char *NL = "\n", unsigned int Space = 0,

1912 bool IsDot = false) const;

1913 void printEquivalenceClasses(raw_ostream &Out, ProgramStateRef State,

1914 const char *NL = "\n", unsigned int Space = 0,

1915 bool IsDot = false) const;

1916 void printDisequalities(raw_ostream &Out, ProgramStateRef State,

1917 const char *NL = "\n", unsigned int Space = 0,

1918 bool IsDot = false) const;

1919

1920

1921

1922

1923

1925 const llvm::APSInt &V,

1926 const llvm::APSInt &Adjustment) override;

1927

1929 const llvm::APSInt &V,

1930 const llvm::APSInt &Adjustment) override;

1931

1933 const llvm::APSInt &V,

1934 const llvm::APSInt &Adjustment) override;

1935

1937 const llvm::APSInt &V,

1938 const llvm::APSInt &Adjustment) override;

1939

1941 const llvm::APSInt &V,

1942 const llvm::APSInt &Adjustment) override;

1943

1945 const llvm::APSInt &V,

1946 const llvm::APSInt &Adjustment) override;

1947

1950 const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;

1951

1954 const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;

1955

1956private:

1958

1962

1964 const llvm::APSInt &Int,

1965 const llvm::APSInt &Adjustment) const;

1967 const llvm::APSInt &Int,

1968 const llvm::APSInt &Adjustment) const;

1970 const llvm::APSInt &Int,

1971 const llvm::APSInt &Adjustment) const;

1973 const llvm::APSInt &Int,

1974 const llvm::APSInt &Adjustment) const;

1976 const llvm::APSInt &Int,

1977 const llvm::APSInt &Adjustment) const;

1978};

1979

1980

1981

1982

1983

1984

1985

1986

1987

1988

1989

1990

1991

1992

1993

1994

1995

1996

1997

1998template class ConstraintAssignorBase {

1999public:

2000 using Const = const llvm::APSInt &;

2001

2002#define DISPATCH(CLASS) return assign##CLASS##Impl(cast(Sym), Constraint)

2003

2004#define ASSIGN(CLASS, TO, SYM, CONSTRAINT) \

2005 if (!static_cast<Derived *>(this)->assign##CLASS##To##TO(SYM, CONSTRAINT)) \

2006 return false

2007

2009 assignImpl(Sym, Constraint);

2010 }

2011

2013 switch (Sym->getKind()) {

2014#define SYMBOL(Id, Parent) \

2015 case SymExpr::Id##Kind: \

2016 DISPATCH(Id);

2017#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"

2018 }

2019 llvm_unreachable("Unknown SymExpr kind!");

2020 }

2021

2022#define DEFAULT_ASSIGN(Id) \

2023 bool assign##Id##To##RangeSet(const Id *Sym, RangeSet Constraint) { \

2024 return true; \

2025 } \

2026 bool assign##Id##To##Range(const Id *Sym, Range Constraint) { return true; } \

2027 bool assign##Id##To##Const(const Id *Sym, Const Constraint) { return true; }

2028

2029

2030

2031

2032

2033#define CONSTRAINT_DISPATCH(Id) \

2034 if (const llvm::APSInt *Const = Constraint.getConcreteValue()) { \

2035 ASSIGN(Id, Const, Sym, *Const); \

2036 } \

2037 if (Constraint.size() == 1) { \

2038 ASSIGN(Id, Range, Sym, *Constraint.begin()); \

2039 } \

2040 ASSIGN(Id, RangeSet, Sym, Constraint)

2041

2042

2043

2044

2045#define SYMBOL(Id, Parent) \

2046 bool assign##Id##Impl(const Id *Sym, RangeSet Constraint) { \

2047 CONSTRAINT_DISPATCH(Id); \

2048 DISPATCH(Parent); \

2049 } \

2050 DEFAULT_ASSIGN(Id)

2051#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)

2052#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"

2053

2054

2055 bool assignSymExprImpl(const SymExpr *Sym, RangeSet Constraint) {

2057 return true;

2058 }

2060

2061#undef DISPATCH

2062#undef CONSTRAINT_DISPATCH

2063#undef DEFAULT_ASSIGN

2064#undef ASSIGN

2065};

2066

2067

2068

2069

2070

2071

2072

2073

2074

2075

2076

2077

2078class ConstraintAssignor : public ConstraintAssignorBase {

2079public:

2080 template

2083 ClassOrSymbol CoS, RangeSet NewConstraint) {

2084 if (!State || NewConstraint.isEmpty())

2085 return nullptr;

2086

2087 ConstraintAssignor Assignor{State, Builder, F};

2088 return Assignor.assign(CoS, NewConstraint);

2089 }

2090

2091

2092 template

2093 bool handleRemainderOp(const SymT *Sym, RangeSet Constraint) {

2094 if (Sym->getOpcode() != BO_Rem)

2095 return true;

2096

2098 SVal SymSVal = Builder.makeSymbolVal(Sym->getLHS());

2100 State = State->assume(*NonLocSymSVal, true);

2101 if (!State)

2102 return false;

2103 }

2104 }

2105 return true;

2106 }

2107

2108 inline bool assignSymExprToConst(const SymExpr *Sym, Const Constraint);

2109 inline bool assignSymIntExprToRangeSet(const SymIntExpr *Sym,

2111 return handleRemainderOp(Sym, Constraint);

2112 }

2113 inline bool assignSymSymExprToRangeSet(const SymSymExpr *Sym,

2115

2116private:

2119 : State(State), Builder(Builder), RangeFactory(F) {}

2120 using Base = ConstraintAssignorBase;

2121

2122

2124

2125

2126 State = assign(EquivalenceClass::find(State, Sym), NewConstraint);

2127 if (!State)

2128 return nullptr;

2129

2130

2131

2132 Base::assign(Sym, NewConstraint);

2133 return State;

2134 }

2135

2136

2137 [[nodiscard]] ProgramStateRef assign(EquivalenceClass Class,

2139

2140

2141

2142

2143

2144 if (const llvm::APSInt *Point = NewConstraint.getConcreteValue()) {

2145

2146 ConstraintRangeTy Constraints = State->get();

2147 ConstraintRangeTy::Factory &CF = State->get_context();

2148

2149

2150 Constraints = CF.add(Constraints, Class, NewConstraint);

2151

2152 for (EquivalenceClass DisequalClass : Class.getDisequalClasses(State)) {

2153 RangeSet UpdatedConstraint = SymbolicRangeInferrer::inferRange(

2154 RangeFactory, State, DisequalClass);

2155

2156 UpdatedConstraint = RangeFactory.deletePoint(UpdatedConstraint, *Point);

2157

2158

2159

2160 if (UpdatedConstraint.isEmpty())

2161 return nullptr;

2162

2163 Constraints = CF.add(Constraints, DisequalClass, UpdatedConstraint);

2164 }

2165 assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "

2166 "a state with infeasible constraints");

2167

2168 return setConstraints(State, Constraints);

2169 }

2170

2171 return setConstraint(State, Class, NewConstraint);

2172 }

2173

2176 return EquivalenceClass::markDisequal(RangeFactory, State, LHS, RHS);

2177 }

2178

2181 return EquivalenceClass::merge(RangeFactory, State, LHS, RHS);

2182 }

2183

2184 [[nodiscard]] std::optional interpreteAsBool(RangeSet Constraint) {

2185 assert(!Constraint.isEmpty() && "Empty ranges shouldn't get here");

2186

2189

2191 return true;

2192

2193 return std::nullopt;

2194 }

2195

2199};

2200

2201bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym,

2202 const llvm::APSInt &Constraint) {

2203 llvm::SmallSet<EquivalenceClass, 4> SimplifiedClasses;

2204

2205 ClassMembersTy Members = State->get();

2206 for (std::pair<EquivalenceClass, SymbolSet> ClassToSymbolSet : Members) {

2207 EquivalenceClass Class = ClassToSymbolSet.first;

2208 State = EquivalenceClass::simplify(Builder, RangeFactory, State, Class);

2209 if (!State)

2210 return false;

2211 SimplifiedClasses.insert(Class);

2212 }

2213

2214

2215

2216

2217 ConstraintRangeTy Constraints = State->get();

2218 for (std::pair<EquivalenceClass, RangeSet> ClassConstraint : Constraints) {

2219 EquivalenceClass Class = ClassConstraint.first;

2220 if (SimplifiedClasses.count(Class))

2221 continue;

2222 State = EquivalenceClass::simplify(Builder, RangeFactory, State, Class);

2223 if (!State)

2224 return false;

2225 }

2226

2227

2228

2229 DisequalityMapTy DisequalityInfo = State->get();

2230 for (std::pair<EquivalenceClass, ClassSet> DisequalityEntry :

2231 DisequalityInfo) {

2232 EquivalenceClass Class = DisequalityEntry.first;

2233 ClassSet DisequalClasses = DisequalityEntry.second;

2234 State = EquivalenceClass::simplify(Builder, RangeFactory, State, Class);

2235 if (!State)

2236 return false;

2237 }

2238

2239 return true;

2240}

2241

2242bool ConstraintAssignor::assignSymSymExprToRangeSet(const SymSymExpr *Sym,

2244 if (!handleRemainderOp(Sym, Constraint))

2245 return false;

2246

2247 std::optional ConstraintAsBool = interpreteAsBool(Constraint);

2248

2249 if (!ConstraintAsBool)

2250 return true;

2251

2252 if (std::optional Equality = meansEquality(Sym)) {

2253

2254

2255

2256

2257

2258 if (*Equality == *ConstraintAsBool) {

2259 State = trackEquality(State, Sym->getLHS(), Sym->getRHS());

2260 } else {

2261

2262 State = trackDisequality(State, Sym->getLHS(), Sym->getRHS());

2263 }

2264

2265 if (!State)

2266 return false;

2267 }

2268

2269 return true;

2270}

2271

2272}

2273

2274std::unique_ptr

2277 return std::make_unique(Eng, StMgr.getSValBuilder());

2278}

2279

2281 ConstraintMap::Factory &F = State->get_context<ConstraintMap>();

2283

2284 ConstraintRangeTy Constraints = State->get();

2285 for (std::pair<EquivalenceClass, RangeSet> ClassConstraint : Constraints) {

2286 EquivalenceClass Class = ClassConstraint.first;

2287 SymbolSet ClassMembers = Class.getClassMembers(State);

2288 assert(!ClassMembers.isEmpty() &&

2289 "Class must always have at least one member!");

2290

2291 SymbolRef Representative = *ClassMembers.begin();

2292 Result = F.add(Result, Representative, ClassConstraint.second);

2293 }

2294

2296}

2297

2298

2299

2300

2301

2302LLVM_DUMP_METHOD void EquivalenceClass::dumpToStream(ProgramStateRef State,

2303 raw_ostream &os) const {

2304 SymbolSet ClassMembers = getClassMembers(State);

2305 for (const SymbolRef &MemberSym : ClassMembers) {

2306 MemberSym->dump();

2307 os << "\n";

2308 }

2309}

2310

2311inline EquivalenceClass EquivalenceClass::find(ProgramStateRef State,

2313 assert(State && "State should not be null");

2314 assert(Sym && "Symbol should not be null");

2315

2316 if (const EquivalenceClass *NontrivialClass = State->get(Sym))

2317 return *NontrivialClass;

2318

2319

2320 return Sym;

2321}

2322

2327 EquivalenceClass FirstClass = find(State, First);

2328 EquivalenceClass SecondClass = find(State, Second);

2329

2330 return FirstClass.merge(F, State, SecondClass);

2331}

2332

2335 EquivalenceClass Other) {

2336

2337 if (*this == Other)

2338 return State;

2339

2340

2341

2342

2343

2344

2345

2346

2347

2348

2349

2350

2351 if (getType()->getCanonicalTypeUnqualified() !=

2352 Other.getType()->getCanonicalTypeUnqualified())

2353 return State;

2354

2355 SymbolSet Members = getClassMembers(State);

2356 SymbolSet OtherMembers = Other.getClassMembers(State);

2357

2358

2359

2360

2361 if (Members.getHeight() >= OtherMembers.getHeight()) {

2362 return mergeImpl(F, State, Members, Other, OtherMembers);

2363 } else {

2364 return Other.mergeImpl(F, State, OtherMembers, *this, Members);

2365 }

2366}

2367

2372

2373

2374

2375

2376

2377

2378

2379

2380

2381

2382

2383 ConstraintRangeTy Constraints = State->get();

2384 ConstraintRangeTy::Factory &CRF = State->get_context();

2385

2386

2387

2388

2389

2390

2391 if (std::optional NewClassConstraint =

2392 intersect(RangeFactory, getConstraint(State, *this),

2393 getConstraint(State, Other))) {

2394

2395

2396

2397

2398

2399 if (NewClassConstraint->isEmpty())

2400

2401 return nullptr;

2402

2403

2404 Constraints = CRF.remove(Constraints, Other);

2405

2406 Constraints = CRF.add(Constraints, *this, *NewClassConstraint);

2407

2408 assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "

2409 "a state with infeasible constraints");

2410

2411 State = State->set(Constraints);

2412 }

2413

2414

2415 ClassMapTy Classes = State->get();

2416 ClassMapTy::Factory &CMF = State->get_context();

2417

2418 ClassMembersTy Members = State->get();

2419 ClassMembersTy::Factory &MF = State->get_context();

2420

2421 DisequalityMapTy DisequalityInfo = State->get();

2422 DisequalityMapTy::Factory &DF = State->get_context();

2423

2424 ClassSet::Factory &CF = State->get_context();

2425 SymbolSet::Factory &F = getMembersFactory(State);

2426

2427

2428 SymbolSet NewClassMembers = MyMembers;

2429 for (SymbolRef Sym : OtherMembers) {

2430 NewClassMembers = F.add(NewClassMembers, Sym);

2431

2432 Classes = CMF.add(Classes, Sym, *this);

2433 }

2434

2435

2436

2437

2438 Members = MF.remove(Members, Other);

2439

2440 Members = MF.add(Members, *this, NewClassMembers);

2441

2442

2443 ClassSet DisequalToOther = Other.getDisequalClasses(DisequalityInfo, CF);

2444

2445

2446 if (DisequalToOther.contains(*this))

2447 return nullptr;

2448

2449 if (!DisequalToOther.isEmpty()) {

2450 ClassSet DisequalToThis = getDisequalClasses(DisequalityInfo, CF);

2451 DisequalityInfo = DF.remove(DisequalityInfo, Other);

2452

2453 for (EquivalenceClass DisequalClass : DisequalToOther) {

2454 DisequalToThis = CF.add(DisequalToThis, DisequalClass);

2455

2456

2457

2458

2459 ClassSet OriginalSetLinkedToOther =

2460 *DisequalityInfo.lookup(DisequalClass);

2461

2462

2463

2464 ClassSet NewSet = CF.remove(OriginalSetLinkedToOther, Other);

2465 NewSet = CF.add(NewSet, *this);

2466

2467 DisequalityInfo = DF.add(DisequalityInfo, DisequalClass, NewSet);

2468 }

2469

2470 DisequalityInfo = DF.add(DisequalityInfo, *this, DisequalToThis);

2471 State = State->set(DisequalityInfo);

2472 }

2473

2474

2475 State = State->set(Classes);

2476 State = State->set(Members);

2477

2478 return State;

2479}

2480

2481inline SymbolSet::Factory &

2482EquivalenceClass::getMembersFactory(ProgramStateRef State) {

2483 return State->get_context<SymbolSet>();

2484}

2485

2487 if (const SymbolSet *Members = State->get(*this))

2488 return *Members;

2489

2490

2491

2492 SymbolSet::Factory &F = getMembersFactory(State);

2493 return F.add(F.getEmptySet(), getRepresentativeSymbol());

2494}

2495

2496bool EquivalenceClass::isTrivial(ProgramStateRef State) const {

2497 return State->get(*this) == nullptr;

2498}

2499

2500bool EquivalenceClass::isTriviallyDead(ProgramStateRef State,

2502 return isTrivial(State) && Reaper.isDead(getRepresentativeSymbol());

2503}

2504

2509 return markDisequal(RF, State, find(State, First), find(State, Second));

2510}

2511

2514 EquivalenceClass First,

2515 EquivalenceClass Second) {

2516 return First.markDisequal(RF, State, Second);

2517}

2518

2521 EquivalenceClass Other) const {

2522

2523

2524 if (*this == Other) {

2525 return nullptr;

2526 }

2527

2528 DisequalityMapTy DisequalityInfo = State->get();

2529 ConstraintRangeTy Constraints = State->get();

2530

2531

2532

2533 if (!addToDisequalityInfo(DisequalityInfo, Constraints, RF, State, *this,

2535 !addToDisequalityInfo(DisequalityInfo, Constraints, RF, State, Other,

2536 *this))

2537 return nullptr;

2538

2539 assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "

2540 "a state with infeasible constraints");

2541

2542 State = State->set(DisequalityInfo);

2543 State = State->set(Constraints);

2544

2545 return State;

2546}

2547

2548inline bool EquivalenceClass::addToDisequalityInfo(

2549 DisequalityMapTy &Info, ConstraintRangeTy &Constraints,

2551 EquivalenceClass Second) {

2552

2553

2554 DisequalityMapTy::Factory &F = State->get_context();

2555 ClassSet::Factory &CF = State->get_context();

2556 ConstraintRangeTy::Factory &CRF = State->get_context();

2557

2558

2559 const ClassSet *CurrentSet = Info.lookup(First);

2560 ClassSet NewSet = CurrentSet ? *CurrentSet : CF.getEmptySet();

2561 NewSet = CF.add(NewSet, Second);

2562

2563 Info = F.add(Info, First, NewSet);

2564

2565

2566

2567

2568

2569

2570 if (const RangeSet *SecondConstraint = Constraints.lookup(Second))

2571 if (const llvm::APSInt *Point = SecondConstraint->getConcreteValue()) {

2572

2573 RangeSet FirstConstraint = SymbolicRangeInferrer::inferRange(

2574 RF, State, First.getRepresentativeSymbol());

2575

2576 FirstConstraint = RF.deletePoint(FirstConstraint, *Point);

2577

2578

2579

2580 if (FirstConstraint.isEmpty())

2581 return false;

2582

2583 Constraints = CRF.add(Constraints, First, FirstConstraint);

2584 }

2585

2586 return true;

2587}

2588

2589inline std::optional EquivalenceClass::areEqual(ProgramStateRef State,

2592 return EquivalenceClass::areEqual(State, find(State, FirstSym),

2593 find(State, SecondSym));

2594}

2595

2596inline std::optional EquivalenceClass::areEqual(ProgramStateRef State,

2597 EquivalenceClass First,

2598 EquivalenceClass Second) {

2599

2600 if (First == Second)

2601 return true;

2602

2603

2604

2605 ClassSet DisequalToFirst = First.getDisequalClasses(State);

2606 if (DisequalToFirst.contains(Second))

2607 return false;

2608

2609

2610 return std::nullopt;

2611}

2612

2615

2616 SymbolSet ClsMembers = getClassMembers(State);

2617 assert(ClsMembers.contains(Old));

2618

2619

2620 SymbolSet::Factory &F = getMembersFactory(State);

2621 ClassMembersTy::Factory &EMFactory = State->get_context();

2622 ClsMembers = F.remove(ClsMembers, Old);

2623

2624

2625 assert(!ClsMembers.isEmpty() &&

2626 "Class should have had at least two members before member removal");

2627

2628 ClassMembersTy ClassMembersMap = State->get();

2629 ClassMembersMap = EMFactory.add(ClassMembersMap, *this, ClsMembers);

2630 State = State->set(ClassMembersMap);

2631

2632

2633 ClassMapTy Classes = State->get();

2634 ClassMapTy::Factory &CMF = State->get_context();

2635 Classes = CMF.remove(Classes, Old);

2636 State = State->set(Classes);

2637

2638 return State;

2639}

2640

2641

2644 if (!Constraint)

2645 return State;

2646

2648

2649

2651 return State->assume(DefinedVal, false);

2652

2653

2654

2656 State = State->assume(DefinedVal, true);

2657 if (!State)

2658 return nullptr;

2659

2660 }

2661

2662

2663 return State->assumeInclusiveRange(DefinedVal, Constraint->getMinValue(),

2665}

2666

2667

2668

2669

2670

2671

2675 SymbolSet ClassMembers = Class.getClassMembers(State);

2676 for (const SymbolRef &MemberSym : ClassMembers) {

2677

2680

2681

2682

2684 const llvm::APSInt &SV = CI->getValue();

2685 const RangeSet *ClassConstraint = getConstraint(State, Class);

2686

2687 if (ClassConstraint && !ClassConstraint->contains(SV))

2688 return nullptr;

2689 }

2690

2691 if (SimplifiedMemberSym && MemberSym != SimplifiedMemberSym) {

2692

2693

2694

2696 State = merge(F, State, MemberSym, SimplifiedMemberSym);

2697 if (!State)

2698 return nullptr;

2699

2700 if (OldState == State)

2701 continue;

2702

2703

2704

2705

2706

2707

2708

2709

2710

2711

2712

2713

2714

2715

2716 State = find(State, MemberSym).removeMember(State, MemberSym);

2717

2718

2719

2720 const RangeSet *ClassConstraint = getConstraint(State, Class);

2721

2722

2723

2724

2725

2726

2727

2728

2729

2730

2731

2732

2733

2734

2735

2736

2737

2738

2739

2740

2741 State = reAssume(State, ClassConstraint, SimplifiedMemberVal);

2742 if (!State)

2743 return nullptr;

2744 }

2745 }

2746 return State;

2747}

2748

2749inline ClassSet EquivalenceClass::getDisequalClasses(ProgramStateRef State,

2751 return find(State, Sym).getDisequalClasses(State);

2752}

2753

2754inline ClassSet

2755EquivalenceClass::getDisequalClasses(ProgramStateRef State) const {

2756 return getDisequalClasses(State->get(),

2757 State->get_context());

2758}

2759

2760inline ClassSet

2761EquivalenceClass::getDisequalClasses(DisequalityMapTy Map,

2762 ClassSet::Factory &Factory) const {

2763 if (const ClassSet *DisequalClasses = Map.lookup(*this))

2764 return *DisequalClasses;

2765

2766 return Factory.getEmptySet();

2767}

2768

2769bool EquivalenceClass::isClassDataConsistent(ProgramStateRef State) {

2770 ClassMembersTy Members = State->get();

2771

2772 for (std::pair<EquivalenceClass, SymbolSet> ClassMembersPair : Members) {

2774

2775 if (find(State, Member) == ClassMembersPair.first) {

2776 continue;

2777 }

2778

2779 return false;

2780 }

2781 }

2782

2783 DisequalityMapTy Disequalities = State->get();

2784 for (std::pair<EquivalenceClass, ClassSet> DisequalityInfo : Disequalities) {

2785 EquivalenceClass Class = DisequalityInfo.first;

2786 ClassSet DisequalClasses = DisequalityInfo.second;

2787

2788

2789 if (DisequalClasses.isEmpty())

2790 return false;

2791

2792

2793

2794 for (EquivalenceClass DisequalClass : DisequalClasses) {

2795 const ClassSet *DisequalToDisequalClasses =

2796 Disequalities.lookup(DisequalClass);

2797

2798

2799 if (!DisequalToDisequalClasses ||

2800 !DisequalToDisequalClasses->contains(Class))

2801 return false;

2802 }

2803 }

2804

2805 return true;

2806}

2807

2808

2809

2810

2811

2812bool RangeConstraintManager::canReasonAbout(SVal X) const {

2813 std::optionalnonloc::SymbolVal SymVal = X.getAs<nonloc::SymbolVal>();

2814 if (SymVal && SymVal->isExpression()) {

2815 const SymExpr *SE = SymVal->getSymbol();

2816

2817 if (const SymIntExpr *SIE = dyn_cast(SE)) {

2818 switch (SIE->getOpcode()) {

2819

2820 case BO_And:

2821 case BO_Or:

2822 case BO_Xor:

2823 return false;

2824

2825

2826 case BO_Mul:

2827 case BO_Div:

2828 case BO_Rem:

2829 case BO_Shl:

2830 case BO_Shr:

2831 return false;

2832

2833 default:

2834 return true;

2835 }

2836 }

2837

2838 if (const SymSymExpr *SSE = dyn_cast(SE)) {

2839

2842

2843

2844

2845

2848 }

2849 }

2850 }

2851

2852 return false;

2853 }

2854

2855 return true;

2856}

2857

2860 const RangeSet *Ranges = getConstraint(State, Sym);

2861

2862

2863 if (!Ranges)

2865

2866

2868 return *Value == 0;

2869

2873

2874

2875 if (!Ranges->contains(Zero))

2876 return false;

2877

2878

2880}

2881

2882const llvm::APSInt *RangeConstraintManager::getSymVal(ProgramStateRef St,

2884 return getRange(St, Sym).getConcreteValue();

2885}

2886

2887const llvm::APSInt *RangeConstraintManager::getSymMinVal(ProgramStateRef St,

2890 return Range.isEmpty() ? nullptr : &Range.getMinValue();

2891}

2892

2893const llvm::APSInt *RangeConstraintManager::getSymMaxVal(ProgramStateRef St,

2896 return Range.isEmpty() ? nullptr : &Range.getMaxValue();

2897}

2898

2899

2900

2901

2902

2903

2904

2906RangeConstraintManager::removeDeadBindings(ProgramStateRef State,

2908 ClassMembersTy ClassMembersMap = State->get();

2909 ClassMembersTy NewClassMembersMap = ClassMembersMap;

2910 ClassMembersTy::Factory &EMFactory = State->get_context();

2911 SymbolSet::Factory &SetFactory = State->get_context<SymbolSet>();

2912

2913 ConstraintRangeTy Constraints = State->get();

2914 ConstraintRangeTy NewConstraints = Constraints;

2915 ConstraintRangeTy::Factory &ConstraintFactory =

2916 State->get_context();

2917

2918 ClassMapTy Map = State->get();

2919 ClassMapTy NewMap = Map;

2920 ClassMapTy::Factory &ClassFactory = State->get_context();

2921

2922 DisequalityMapTy Disequalities = State->get();

2923 DisequalityMapTy::Factory &DisequalityFactory =

2924 State->get_context();

2925 ClassSet::Factory &ClassSetFactory = State->get_context();

2926

2927 bool ClassMapChanged = false;

2928 bool MembersMapChanged = false;

2929 bool ConstraintMapChanged = false;

2930 bool DisequalitiesChanged = false;

2931

2932 auto removeDeadClass = [&](EquivalenceClass Class) {

2933

2934 Constraints = ConstraintFactory.remove(Constraints, Class);

2935 ConstraintMapChanged = true;

2936

2937

2938

2939 ClassSet DisequalClasses =

2940 Class.getDisequalClasses(Disequalities, ClassSetFactory);

2941 if (!DisequalClasses.isEmpty()) {

2942 for (EquivalenceClass DisequalClass : DisequalClasses) {

2943 ClassSet DisequalToDisequalSet =

2944 DisequalClass.getDisequalClasses(Disequalities, ClassSetFactory);

2945

2946

2947 assert(!DisequalToDisequalSet.isEmpty());

2948 ClassSet NewSet = ClassSetFactory.remove(DisequalToDisequalSet, Class);

2949

2950

2951 if (NewSet.isEmpty()) {

2952 Disequalities =

2953 DisequalityFactory.remove(Disequalities, DisequalClass);

2954 } else {

2955 Disequalities =

2956 DisequalityFactory.add(Disequalities, DisequalClass, NewSet);

2957 }

2958 }

2959

2960 Disequalities = DisequalityFactory.remove(Disequalities, Class);

2961 DisequalitiesChanged = true;

2962 }

2963 };

2964

2965

2966 for (std::pair<EquivalenceClass, RangeSet> ClassConstraintPair :

2967 Constraints) {

2968 EquivalenceClass Class = ClassConstraintPair.first;

2969 if (Class.isTriviallyDead(State, SymReaper)) {

2970

2971 removeDeadClass(Class);

2972 }

2973 }

2974

2975

2976 for (std::pair<SymbolRef, EquivalenceClass> SymbolClassPair : Map) {

2977 SymbolRef Sym = SymbolClassPair.first;

2978

2979 if (SymReaper.isDead(Sym)) {

2980 ClassMapChanged = true;

2981 NewMap = ClassFactory.remove(NewMap, Sym);

2982 }

2983 }

2984

2985

2986

2987 for (std::pair<EquivalenceClass, SymbolSet> ClassMembersPair :

2988 ClassMembersMap) {

2989 EquivalenceClass Class = ClassMembersPair.first;

2990 SymbolSet LiveMembers = ClassMembersPair.second;

2991 bool MembersChanged = false;

2992

2995 MembersChanged = true;

2996 LiveMembers = SetFactory.remove(LiveMembers, Member);

2997 }

2998 }

2999

3000

3001 if (!MembersChanged)

3002 continue;

3003

3004 MembersMapChanged = true;

3005

3006 if (LiveMembers.isEmpty()) {

3007

3008 NewClassMembersMap = EMFactory.remove(NewClassMembersMap, Class);

3009

3010

3011 removeDeadClass(Class);

3012 } else {

3013

3014 NewClassMembersMap =

3015 EMFactory.add(NewClassMembersMap, Class, LiveMembers);

3016 }

3017 }

3018

3019

3020

3021

3022 if (ClassMapChanged)

3023 State = State->set(NewMap);

3024

3025 if (MembersMapChanged)

3026 State = State->set(NewClassMembersMap);

3027

3028 if (ConstraintMapChanged)

3029 State = State->set(Constraints);

3030

3031 if (DisequalitiesChanged)

3032 State = State->set(Disequalities);

3033

3034 assert(EquivalenceClass::isClassDataConsistent(State));

3035

3036 return State;

3037}

3038

3041 return SymbolicRangeInferrer::inferRange(F, State, Sym);

3042}

3043

3047 return ConstraintAssignor::assign(State, getSValBuilder(), F, Sym, Range);

3048}

3049

3050

3051

3052

3053

3054

3055

3056

3057

3058

3059

3060

3061

3064 const llvm::APSInt &Int,

3065 const llvm::APSInt &Adjustment) {

3066

3067 APSIntType AdjustmentType(Adjustment);

3069 return St;

3070

3071 llvm::APSInt Point = AdjustmentType.convert(Int) - Adjustment;

3074

3075 return setRange(St, Sym, New);

3076}

3077

3080 const llvm::APSInt &Int,

3081 const llvm::APSInt &Adjustment) {

3082

3083 APSIntType AdjustmentType(Adjustment);

3085 return nullptr;

3086

3087

3088 llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment;

3091

3092 return setRange(St, Sym, New);

3093}

3094

3097 const llvm::APSInt &Int,

3098 const llvm::APSInt &Adjustment) const {

3099

3100 APSIntType AdjustmentType(Adjustment);

3101 switch (AdjustmentType.testInRange(Int, true)) {

3105 break;

3108 }

3109

3110

3111 llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);

3112 llvm::APSInt Min = AdjustmentType.getMinValue();

3113 if (ComparisonVal == Min)

3115

3116 llvm::APSInt Lower = Min - Adjustment;

3117 llvm::APSInt Upper = ComparisonVal - Adjustment;

3118 --Upper;

3119

3122}

3123

3126 const llvm::APSInt &Int,

3127 const llvm::APSInt &Adjustment) {

3128 RangeSet New = getSymLTRange(St, Sym, Int, Adjustment);

3129 return setRange(St, Sym, New);

3130}

3131

3134 const llvm::APSInt &Int,

3135 const llvm::APSInt &Adjustment) const {

3136

3137 APSIntType AdjustmentType(Adjustment);

3138 switch (AdjustmentType.testInRange(Int, true)) {

3142 break;

3145 }

3146

3147

3148 llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);

3149 llvm::APSInt Max = AdjustmentType.getMaxValue();

3150 if (ComparisonVal == Max)

3152

3153 llvm::APSInt Lower = ComparisonVal - Adjustment;

3154 llvm::APSInt Upper = Max - Adjustment;

3155 ++Lower;

3156

3158 return F.intersect(SymRange, Lower, Upper);

3159}

3160

3163 const llvm::APSInt &Int,

3164 const llvm::APSInt &Adjustment) {

3165 RangeSet New = getSymGTRange(St, Sym, Int, Adjustment);

3166 return setRange(St, Sym, New);

3167}

3168

3171 const llvm::APSInt &Int,

3172 const llvm::APSInt &Adjustment) const {

3173

3174 APSIntType AdjustmentType(Adjustment);

3175 switch (AdjustmentType.testInRange(Int, true)) {

3179 break;

3182 }

3183

3184

3185 llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);

3186 llvm::APSInt Min = AdjustmentType.getMinValue();

3187 if (ComparisonVal == Min)

3189

3190 llvm::APSInt Max = AdjustmentType.getMaxValue();

3191 llvm::APSInt Lower = ComparisonVal - Adjustment;

3192 llvm::APSInt Upper = Max - Adjustment;

3193

3195 return F.intersect(SymRange, Lower, Upper);

3196}

3197

3200 const llvm::APSInt &Int,

3201 const llvm::APSInt &Adjustment) {

3202 RangeSet New = getSymGERange(St, Sym, Int, Adjustment);

3203 return setRange(St, Sym, New);

3204}

3205

3207RangeConstraintManager::getSymLERange(llvm::function_ref<RangeSet()> RS,

3208 const llvm::APSInt &Int,

3209 const llvm::APSInt &Adjustment) const {

3210

3211 APSIntType AdjustmentType(Adjustment);

3212 switch (AdjustmentType.testInRange(Int, true)) {

3216 break;

3218 return RS();

3219 }

3220

3221

3222 llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);

3223 llvm::APSInt Max = AdjustmentType.getMaxValue();

3224 if (ComparisonVal == Max)

3225 return RS();

3226

3227 llvm::APSInt Min = AdjustmentType.getMinValue();

3228 llvm::APSInt Lower = Min - Adjustment;

3229 llvm::APSInt Upper = ComparisonVal - Adjustment;

3230

3233}

3234

3237 const llvm::APSInt &Int,

3238 const llvm::APSInt &Adjustment) const {

3239 return getSymLERange([&] { return getRange(St, Sym); }, Int, Adjustment);

3240}

3241

3244 const llvm::APSInt &Int,

3245 const llvm::APSInt &Adjustment) {

3246 RangeSet New = getSymLERange(St, Sym, Int, Adjustment);

3247 return setRange(St, Sym, New);

3248}

3249

3250ProgramStateRef RangeConstraintManager::assumeSymWithinInclusiveRange(

3252 const llvm::APSInt &To, const llvm::APSInt &Adjustment) {

3253 RangeSet New = getSymGERange(State, Sym, From, Adjustment);

3255 return nullptr;

3256 RangeSet Out = getSymLERange([&] { return New; }, To, Adjustment);

3257 return setRange(State, Sym, Out);

3258}

3259

3260ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange(

3262 const llvm::APSInt &To, const llvm::APSInt &Adjustment) {

3263 RangeSet RangeLT = getSymLTRange(State, Sym, From, Adjustment);

3264 RangeSet RangeGT = getSymGTRange(State, Sym, To, Adjustment);

3266 return setRange(State, Sym, New);

3267}

3268

3269

3270

3271

3272

3273void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State,

3274 const char *NL, unsigned int Space,

3275 bool IsDot) const {

3276 printConstraints(Out, State, NL, Space, IsDot);

3277 printEquivalenceClasses(Out, State, NL, Space, IsDot);

3278 printDisequalities(Out, State, NL, Space, IsDot);

3279}

3280

3281void RangeConstraintManager::printValue(raw_ostream &Out, ProgramStateRef State,

3285 Out << "";

3286 return;

3287 }

3289 RS.dump(Out);

3290}

3291

3293 std::string S;

3294 llvm::raw_string_ostream O(S);

3296 return S;

3297}

3298

3299void RangeConstraintManager::printConstraints(raw_ostream &Out,

3301 const char *NL,

3302 unsigned int Space,

3303 bool IsDot) const {

3304 ConstraintRangeTy Constraints = State->get();

3305

3306 Indent(Out, Space, IsDot) << "\"constraints\": ";

3307 if (Constraints.isEmpty()) {

3308 Out << "null," << NL;

3309 return;

3310 }

3311

3312 std::map<std::string, RangeSet> OrderedConstraints;

3313 for (std::pair<EquivalenceClass, RangeSet> P : Constraints) {

3314 SymbolSet ClassMembers = P.first.getClassMembers(State);

3315 for (const SymbolRef &ClassMember : ClassMembers) {

3316 bool insertion_took_place;

3317 std::tie(std::ignore, insertion_took_place) =

3318 OrderedConstraints.insert({toString(ClassMember), P.second});

3319 assert(insertion_took_place &&

3320 "two symbols should not have the same dump");

3321 }

3322 }

3323

3324 ++Space;

3325 Out << '[' << NL;

3326 bool First = true;

3327 for (std::pair<std::string, RangeSet> P : OrderedConstraints) {

3330 } else {

3331 Out << ',';

3332 Out << NL;

3333 }

3334 Indent(Out, Space, IsDot)

3335 << "{ \"symbol\": \"" << P.first << "\", \"range\": \"";

3336 P.second.dump(Out);

3337 Out << "\" }";

3338 }

3339 Out << NL;

3340

3341 --Space;

3342 Indent(Out, Space, IsDot) << "]," << NL;

3343}

3344

3346 SymbolSet ClassMembers = Class.getClassMembers(State);

3348 ClassMembers.end());

3349 llvm::sort(ClassMembersSorted,

3352 });

3353

3354 bool FirstMember = true;

3355

3356 std::string Str;

3357 llvm::raw_string_ostream Out(Str);

3358 Out << "[ ";

3359 for (SymbolRef ClassMember : ClassMembersSorted) {

3360 if (FirstMember)

3361 FirstMember = false;

3362 else

3363 Out << ", ";

3364 Out << "\"" << ClassMember << "\"";

3365 }

3366 Out << " ]";

3367 return Str;

3368}

3369

3370void RangeConstraintManager::printEquivalenceClasses(raw_ostream &Out,

3372 const char *NL,

3373 unsigned int Space,

3374 bool IsDot) const {

3375 ClassMembersTy Members = State->get();

3376

3377 Indent(Out, Space, IsDot) << "\"equivalence_classes\": ";

3378 if (Members.isEmpty()) {

3379 Out << "null," << NL;

3380 return;

3381 }

3382

3383 std::setstd::string MembersStr;

3384 for (std::pair<EquivalenceClass, SymbolSet> ClassToSymbolSet : Members)

3385 MembersStr.insert(toString(State, ClassToSymbolSet.first));

3386

3387 ++Space;

3388 Out << '[' << NL;

3389 bool FirstClass = true;

3390 for (const std::string &Str : MembersStr) {

3391 if (FirstClass) {

3392 FirstClass = false;

3393 } else {

3394 Out << ',';

3395 Out << NL;

3396 }

3397 Indent(Out, Space, IsDot);

3398 Out << Str;

3399 }

3400 Out << NL;

3401

3402 --Space;

3403 Indent(Out, Space, IsDot) << "]," << NL;

3404}

3405

3406void RangeConstraintManager::printDisequalities(raw_ostream &Out,

3408 const char *NL,

3409 unsigned int Space,

3410 bool IsDot) const {

3411 DisequalityMapTy Disequalities = State->get();

3412

3413 Indent(Out, Space, IsDot) << "\"disequality_info\": ";

3414 if (Disequalities.isEmpty()) {

3415 Out << "null," << NL;

3416 return;

3417 }

3418

3419

3420

3421 using EqClassesStrTy = std::setstd::string;

3422 using DisequalityInfoStrTy = std::map<std::string, EqClassesStrTy>;

3423 DisequalityInfoStrTy DisequalityInfoStr;

3424 for (std::pair<EquivalenceClass, ClassSet> ClassToDisEqSet : Disequalities) {

3425 EquivalenceClass Class = ClassToDisEqSet.first;

3426 ClassSet DisequalClasses = ClassToDisEqSet.second;

3427 EqClassesStrTy MembersStr;

3428 for (EquivalenceClass DisEqClass : DisequalClasses)

3429 MembersStr.insert(toString(State, DisEqClass));

3430 DisequalityInfoStr.insert({toString(State, Class), MembersStr});

3431 }

3432

3433 ++Space;

3434 Out << '[' << NL;

3435 bool FirstClass = true;

3436 for (std::pair<std::string, EqClassesStrTy> ClassToDisEqSet :

3437 DisequalityInfoStr) {

3438 const std::string &Class = ClassToDisEqSet.first;

3439 if (FirstClass) {

3440 FirstClass = false;

3441 } else {

3442 Out << ',';

3443 Out << NL;

3444 }

3445 Indent(Out, Space, IsDot) << "{" << NL;

3446 unsigned int DisEqSpace = Space + 1;

3447 Indent(Out, DisEqSpace, IsDot) << "\"class\": ";

3449 const EqClassesStrTy &DisequalClasses = ClassToDisEqSet.second;

3450 if (!DisequalClasses.empty()) {

3451 Out << "," << NL;

3452 Indent(Out, DisEqSpace, IsDot) << "\"disequal_to\": [" << NL;

3453 unsigned int DisEqClassSpace = DisEqSpace + 1;

3454 Indent(Out, DisEqClassSpace, IsDot);

3455 bool FirstDisEqClass = true;

3456 for (const std::string &DisEqClass : DisequalClasses) {

3457 if (FirstDisEqClass) {

3458 FirstDisEqClass = false;

3459 } else {

3460 Out << ',' << NL;

3461 Indent(Out, DisEqClassSpace, IsDot);

3462 }

3463 Out << DisEqClass;

3464 }

3465 Out << "]" << NL;

3466 }

3467 Indent(Out, Space, IsDot) << "}";

3468 }

3469 Out << NL;

3470

3471 --Space;

3472 Indent(Out, Space, IsDot) << "]," << NL;

3473}

static bool isTrivial(ASTContext &Ctx, const Expr *E)

Checks if the expression is constant or does not have non-trivial function calls.

static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)

llvm::MachO::SymbolSet SymbolSet

#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)

Declares an immutable map of type NameTy, suitable for placement into the ProgramState.

#define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem)

Declares an immutable set type Name and registers the factory for such sets in the program state,...

#define CONSTRAINT_DISPATCH(Id)

static void swapIterators(T &First, T &FirstEnd, T &Second, T &SecondEnd)

static ProgramStateRef reAssume(ProgramStateRef State, const RangeSet *Constraint, SVal TheValue)

#define DEFAULT_ASSIGN(Id)

static std::string toString(const clang::SanitizerSet &Sanitizers)

Produce a string containing comma-separated names of sanitizers in Sanitizers set.

static CharSourceRange getRange(const CharSourceRange &EditRange, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeMacroExpansion)

static BinaryOperatorKind getOpFromIndex(size_t Index)

constexpr size_t getCmpOpCount() const

TriStateKind getCmpOpState(BinaryOperatorKind CurrentOP, BinaryOperatorKind QueriedOP) const

TriStateKind getCmpOpStateForUnknownX2(BinaryOperatorKind CurrentOP) const

bool isComparisonOp() const

bool isRelationalOp() const

static Opcode negateComparisonOp(Opcode Opc)

static Opcode reverseComparisonOp(Opcode Opc)

bool isEqualityOp() const

A (possibly-)qualified type.

The base class of the type hierarchy.

bool isSignedIntegerOrEnumerationType() const

Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...

bool isUnsignedIntegerOrEnumerationType() const

Determines whether this is an integer type that is unsigned or an enumeration types whose underlying ...

bool isReferenceType() const

bool isIntegralOrEnumerationType() const

Determine whether this type is an integral or enumeration type.

A record of the "type" of an APSInt, used for conversions.

llvm::APSInt getZeroValue() const LLVM_READONLY

Returns an all-zero value for this type.

RangeTestResultKind

Used to classify whether a value is representable using this type.

@ RTR_Within

Value is representable using this type.

@ RTR_Below

Value is less than the minimum representable value.

@ RTR_Above

Value is greater than the maximum representable value.

uint32_t getBitWidth() const

RangeTestResultKind testInRange(const llvm::APSInt &Val, bool AllowMixedSign) const LLVM_READONLY

Tests whether a given value is losslessly representable using this type.

void apply(llvm::APSInt &Value) const

Convert a given APSInt, in place, to match this type.

llvm::APSInt getMinValue() const LLVM_READONLY

Returns the minimum value for this type.

llvm::APSInt convert(const llvm::APSInt &Value) const LLVM_READONLY

Convert and return a new APSInt with the given value, but this type's bit width and signedness.

llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY

APSIntType getAPSIntType(QualType T) const

Returns the type of the APSInt used to store values of the given QualType.

Template implementation for all binary symbolic expressions.

QualType getType() const override

BinaryOperator::Opcode getOpcode() const

static bool isLocType(QualType T)

SValBuilder & getSValBuilder()

RangeSet unite(RangeSet LHS, RangeSet RHS)

Create a new set which is a union of two given ranges.

RangeSet negate(RangeSet What)

Negate the given range set.

RangeSet intersect(RangeSet LHS, RangeSet RHS)

Intersect the given range sets.

RangeSet deletePoint(RangeSet From, const llvm::APSInt &Point)

Delete the given point from the range set.

RangeSet getRangeSet(Range Origin)

Create a new set with just one range.

RangeSet add(RangeSet LHS, RangeSet RHS)

Create a new set with all ranges from both LHS and RHS.

RangeSet castTo(RangeSet What, APSIntType Ty)

Performs promotions, truncations and conversions of the given set.

persistent set of non-overlapping ranges.

const_iterator end() const

APSIntType getAPSIntType() const

const llvm::APSInt & getMaxValue() const

Get the maximal value covered by the ranges in the set.

bool encodesTrueRange() const

Test if the range doesn't contain zero.

bool encodesFalseRange() const

Test if the range is the [0,0] range.

const_iterator begin() const

const llvm::APSInt & getMinValue() const

Get the minimal value covered by the ranges in the set.

ImplType::const_iterator const_iterator

bool contains(llvm::APSInt Point) const

Test whether the given point is contained by any of the ranges.

void dump(raw_ostream &OS) const

bool containsZero() const

uint32_t getBitWidth() const

const llvm::APSInt * getConcreteValue() const

getConcreteValue - If a symbol is constrained to equal a specific integer constant then this method r...

A Range represents the closed range [from, to].

const llvm::APSInt & From() const

void dump(raw_ostream &OS) const

bool Includes(const llvm::APSInt &Point) const

const llvm::APSInt & To() const

SVal - This represents a symbolic expression, which can be either an L-value or an R-value.

SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const

If this SVal wraps a symbol return that SymbolRef.

std::optional< T > getAs() const

Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.

T castAs() const

Convert to the specified SVal type, asserting that this SVal is of the desired type.

SymExprVisitor - this class implements a simple visitor for SymExpr subclasses.

virtual void dumpToStream(raw_ostream &os) const

virtual QualType getType() const =0

const SymExprT * acquire(Args &&...args)

Create or retrieve a SymExpr of type SymExprT for the given arguments.

A class responsible for cleaning up unused symbols.

bool isDead(SymbolRef sym)

Returns whether or not a symbol has been confirmed dead.

Represents a symbolic expression involving a unary operator.

QualType getType() const override

UnaryOperator::Opcode getOpcode() const

const SymExpr * getOperand() const

Value representing integer constant.

Represents symbolic expression that isn't a location.

SVal simplifyToSVal(ProgramStateRef State, SymbolRef Sym)

Try to simplify a given symbolic expression's associated SVal based on the constraints in State.

llvm::ImmutableMap< SymbolRef, RangeSet > ConstraintMap

SymbolRef simplify(ProgramStateRef State, SymbolRef Sym)

Try to simplify a given symbolic expression based on the constraints in State.

@ OS

Indicates that the tracking object is a descendant of a referenced-counted OSObject,...

@ CF

Indicates that the tracked object is a CF object.

std::unique_ptr< ConstraintManager > CreateRangeConstraintManager(ProgramStateManager &statemgr, ExprEngine *exprengine)

ConstraintMap getConstraintMap(ProgramStateRef State)

bool Zero(InterpState &S, CodePtr OpPC)

bool Const(InterpState &S, CodePtr OpPC, const T &Arg)

The JSON file list parser is used to communicate input to InstallAPI.

bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)

bool operator<(DeclarationName LHS, DeclarationName RHS)

Ordering on two declaration names.

@ Result

The result type of a method or function.

bool operator!=(CanQual< T > x, CanQual< U > y)

const FunctionProtoType * T

@ Class

The "class" keyword introduces the elaborated-type-specifier.

@ Other

Other implicit parameter.

__UINTPTR_TYPE__ uintptr_t

An unsigned integer type with the property that any valid pointer to void can be converted to this ty...