The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani...
-
Upload
ethan-cooper -
Category
Documents
-
view
217 -
download
1
Transcript of The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani...
![Page 1: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/1.jpg)
The SLAM Project:Debugging System Software via Static Analysis
Thomas BallSriram K. Rajamani
Microsoft Researchhttp://research.microsoft.com/slam/
![Page 2: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/2.jpg)
Thanks To
Sagar Chaki (CMU) Satyaki Das (Stanford) Rupak Majumdar (UC Berkeley) Todd Millstein (U. Washington) Robby (KSU) Westley Weimer (UC Berkeley)
Andreas Podelski (MPI) Stefan Schwoon (U. Edinburgh)
Software Productivity Tools Research group at MSR
![Page 3: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/3.jpg)
SLAM Agenda
Overview
Demo
Termination (of SLAM)
Termination (of talk)
![Page 4: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/4.jpg)
Specifying and Checking Properties of Programs
Goals defect detection partial validation
Properties memory safety temporal safety security …
Many (mature) techniquesautomated deductionprogram analysistype checkingmodel checking
Many projectsBandera, ESC-Java, FeaVer, JPF, LClint, OSQ, PolyScope, PREfix, rccjava, TVLA, Verisoft, Vault, xgcc, …
![Page 5: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/5.jpg)
Code
ProgrammingTesting
APIUsage Rules
![Page 6: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/6.jpg)
Windows Device Drivers Kernel presents a very complex interface to driver
stack of drivers NT kernel multi-threaded IRP completion, IRQL, plug-n-play, power management,
…
Correct API usage described by finite state protocols
Automatically check that clients respect these protocols
![Page 7: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/7.jpg)
MPR3
CallDriver
MPRcompletion
synch
not pending returned
SKIP2
IPCCallDriver
Skip returnchild status
DC
Completerequest
returnnot Pend
PPCprop
completion
CallDriver
N/A
no propcompletion
CallDriver
start NP
returnPending
NP
MPR1
MPRcompletion
SKIP2
IPCCallDriver
CallDriver
DC
Completerequest
PPCprop
completion
CallDriver
N/A
no propcompletion
CallDriver
start P Mark Pending
IRP accessible N/A
synch
SKIP1CallDriver
SKIP1Skip
MPR2 MPR1
NP
MPR3
CallDrivernot pending returned
MPR2
synch
![Page 8: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/8.jpg)
The SLAM Thesis
We can soundly and precisely check a program without annotations against API rules by creating a program abstraction exploring the abstraction’s state space refining the abstraction
We can scale such an approach to many 100kloc via modular analysis model checking
![Page 9: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/9.jpg)
SLAM Input
API usage rules client C source code “as is”
Analysis create, explore and refine boolean program
abstractions
Output Error traces (minimize noise) Verification (soundness)
![Page 10: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/10.jpg)
Usage Rule for Locking
Unlocked Locked Error
U
L
L
U
state {
int locked = 0;
}
KeAcquireSpinLock.call {
if (locked==1) abort;
else locked = 1;
}
KeReleaseSpinLock.call {
if (locked==0) abort;
else locked = 0;
}
SLICState Machine
![Page 11: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/11.jpg)
Example
do { //get the write lock
KeAcquireSpinLock(&devExt->writeListLock);
nPacketsOld = nPackets; request = devExt->WLHeadVa;
if (request){KeReleaseSpinLock(&devExt->writeListLock);...nPackets++;
}} while (nPackets != nPacketsOld);KeReleaseSpinLock(&devExt->writeListLock);
Loop Invariant: nPackets = nPacketsOld IFF lock is held
![Page 12: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/12.jpg)
c2bp
bebop
newton
prog. P’prog. P
SLIC rules
The SLAM Process
boolean program
path p
predicates
predicates
slic
![Page 13: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/13.jpg)
Instrumented Codedo { //get the write lock
SLIC_KeAcquireSpinLock_call();KeAcquireSpinLock(&devExt->writeListLock);
nPacketsOld = nPackets; request = devExt->WLHeadVa;
if (request){SLIC_KeReleaseSpinLock_call();KeReleaseSpinLock(&devExt->writeListLock);...nPackets++;
}} while (nPackets != nPacketsOld);SLIC_KeReleaseSpinLock_call();KeReleaseSpinLock(&devExt->writeListLock);
![Page 14: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/14.jpg)
Predicate Abstraction of C (c2bp)
Input: a C program P and set of predicates E predicate = pure C boolean expression
Output: a boolean program bp(P,E) that is a sound abstraction of P a precise (boolean) abstraction of P
Results separate compilation (predicate abstraction) in
presence of procedures and pointers
![Page 15: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/15.jpg)
Skeletal Boolean Program
do //get the write lock
SLIC_KeAcquireSpinLock_call();
if (*) then SLIC_KeReleaseSpinLock_call();
fiwhile (*);SLIC_KeReleaseSpinLock_call();
Predicates:
(locked==0)(locked==1)
![Page 16: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/16.jpg)
Reachability in Boolean Programs (bebop)
Symbolic interprocedural data flow analysis Based on CFL-reachability [Reps-Horwitz-Sagiv 95] Explicit representation of CFG Implicit representation of reachable states via BDDs
Worst-case complexity is O( P (GL)3 ) P = program size G = number of global states in state machine L = max. number of local states over all procedures
![Page 17: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/17.jpg)
Shortest Error Path (Acquire 2x)
do //get the write lock
SLIC_KeAcquireSpinLock_call();
if (*) then SLIC_KeReleaseSpinLock_call();
fiwhile (*);SLIC_KeReleaseSpinLock_call();
Predicates:
(locked==0)(locked==1)
![Page 18: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/18.jpg)
Counterexample-driven Refinement (newton)
Symbolically execute path in C program
Check for path infeasibility at each conditional Simplify theorem prover
If path is infeasible, generate new predicates to rule out infeasible path heuristics to generate “weak” explanation
![Page 19: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/19.jpg)
Error Path in C code
do { //get the write lock
KeAcquireSpinLock(&devExt->writeListLock);
nPacketsOld = nPackets; request = devExt->WLHeadVa;
if (request){KeReleaseSpinLock(&devExt->writeListLock);...nPackets++;
}} while (nPackets != nPacketsOld);KeReleaseSpinLock(&devExt->writeListLock);
![Page 20: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/20.jpg)
Newton: Path Simulation
Store:
Conditions:
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 21: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/21.jpg)
Newton
Store:
(1) nPacketsOld:
Conditions:
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 22: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/22.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
Conditions:
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 23: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/23.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
Conditions:
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 24: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/24.jpg)
Newton
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
Conditions:
![Page 25: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/25.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 26: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/26.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
! (5)
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 27: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/27.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
! (5)
!= (1,2)
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 28: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/28.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
(3) devExt:
(4) ->WLHeadVa: (3)
(5) request: (3,4)
Conditions:
!= (1,2)
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 29: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/29.jpg)
Newton
Store:
(1) nPacketsOld:
(2) nPackets: (1)
Conditions:
!= (1,2)
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 30: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/30.jpg)
Newton
Predicates:
(nPacketsOld == )
(nPackets == )
( != )
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 31: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/31.jpg)
Newton
Predicates:
(nPacketsOld != nPackets)
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 32: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/32.jpg)
Newton
Predicates:
(nPacketsOld == nPackets)
nPackets = nPacketsOld;
request = devExt->WLHeadVa;
assume(!request);
assume(nPackets != nPacketsOld);
![Page 33: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/33.jpg)
Refined Boolean Program
do //get the write lock
SLIC_KeAcquireSpinLock_call();b := true; // npacketsOld = npackets;
if (*) then SLIC_KeReleaseSpinLock_call();
b := b ? false : *; // npackets++;fi
while ( !b ); // (nPackets != nPacketsOld);SLIC_KeReleaseSpinLock_call();
Boolean variable b represents the condition
(nPacketsOld==nPackets)
!b
b
b
b
b
b
!b
![Page 34: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/34.jpg)
Results on Drivers (so far)
Handful of drivers analyzed so far 2k-30k of C code each
Each driver has yielded bugs
SLAM process has always terminated minutes to ½ hour
Process optimizations have huge effects
![Page 35: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/35.jpg)
Demo
Lock example validation
Lock example with bug error trace
SLAM’s first bug floppy device driver
![Page 36: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/36.jpg)
Termination of SLAM
[Cousot-Cousot, PLILP’92] widening + abstract interpretation with infinite lattices
(WAIL) is more powerful than a (single) finite abstraction
[Ball-Podelski-Rajamani, TACAS’02] finite abstractions plus iterative refinement (FAIR) is more
powerful than WAIL
![Page 37: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/37.jpg)
Termination and Widening
Widening is used to achieve termination by enlarging the set of states (to reach a fixpoint) 5 x 10 widened to 5 x
Of course, widening may lose precision
Every fixpoint algorithm that loses precision (in order to terminate) uses widening (implicitly)
![Page 38: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/38.jpg)
Fixpoint
X := init;while X S do X’ := X F(X) if X’ X then break
X := X’odreturn X S
X := init;while X S do X’ := X F(X) if X’ X then break i := oracle’s guess X := W(i, X’)odreturn X S
Fixpoint + Widening(WAIL)
![Page 39: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/39.jpg)
F
F
F
F
F
F
W
F
W
F
F
WF
F
W
F
W
Search Space of Widenings
![Page 40: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/40.jpg)
Finite Abstraction + Iterative Refinement
X := init; while true do P := atoms(X); X# := lfp(F#
P, init)
if X# S then break X := X F(X)odreturn X# S
If WAIL succeeds in N iterations then FAIR will succeed in N iterations
But, FAIR can succeed earlier, due to use of interior (abstract) fixpoint
![Page 41: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/41.jpg)
Search Space
F
F
F
F
F
F
W
F
W
F
F
WF
F
W
F
W
F
F
F
F
F
WAIL+oracle FAIR
![Page 42: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/42.jpg)
Searching for Solutions
Once upon a time, only a human could play a great game of chess… … but then smart brute force won the day (Deep Blue vs.
Kasparov)
Once upon a time, only a human could design a great abstraction…
![Page 43: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/43.jpg)
Termination of Talk
SLAM automatically discovers inductive invariants viapredicate abstraction of C programsmodel checking of boolean programscounterexample-driven refinement
Implemented and starting to yield results on NT device drivers
![Page 44: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/44.jpg)
SLAMming on the shoulders of …
Model checking predicate abstraction counterexample-driven
refinement BDDs and symbolic model
checking
Program analysis abstract interpretation points-to analysis dataflow via CFL-
reachability
Automated deduction weakest preconditions theorem proving
Software AST toolkit Das’s Golf CU and CMU BDD Simplify, Vampyre OCAML
![Page 45: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/45.jpg)
SLAM Future Work More impact
Static Driver Verifier (internal, external)
More features Heap abstractions Concurrency
More languages C# and CIL
More users 2002 public release of SLAM toolkit
![Page 46: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/46.jpg)
Predictions
The holy grail of full program verification has been abandoned
New checking tools will emerge and be widely used
Tools will exploit ideas from various analysis disciplines alleviate the “chicken-and-egg” problem of
specifications
![Page 47: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/47.jpg)
Challenges / SLAM Reading List
Specifications Mining specifications
Abstractions Predicate abstraction for software verification
Annotations Types as models: model checking MP programs Role analysis
Soundness Ccured: type-safe retrofitting of legacy code
Scaling Lazy abstraction
![Page 48: The SLAM Project: Debugging System Software via Static Analysis Thomas Ball Sriram K. Rajamani Microsoft Research](https://reader033.fdocuments.in/reader033/viewer/2022052522/55147569550346284e8b626c/html5/thumbnails/48.jpg)
The End