├── ChironCore ├── cfg │ ├── __init__.py │ ├── ChironCFG.py │ └── cfgBuilder.py ├── ChironAST │ ├── __init__.py │ ├── ChironAST.py │ └── builder.py ├── interfaces │ ├── __init__.py │ ├── fuzzerInterface.py │ └── sExecutionInterface.py ├── turtparse │ ├── __init__.py │ ├── parseError.py │ ├── tlang.tokens │ ├── tlangLexer.tokens │ ├── tlang.g4 │ ├── tlangVisitor.py │ ├── tlang.interp │ ├── tlangLexer.interp │ └── tlangLexer.py ├── example │ ├── exampleSE.tl │ ├── kachuapur.tl │ ├── control_flow_graph.png │ ├── kachuapur2.tl │ ├── example1.tl │ └── example2.tl ├── ChironHooks │ ├── tenor.gif │ └── Chironhooks.py ├── extlib │ └── antlr-4.7.2-complete.jar ├── dataFlowAnalysis.py ├── z3solver.py ├── lattice.py ├── LICENSE ├── irhandler.py ├── abstractInterpretation.py ├── interpreter.py ├── fuzzer.py ├── sExecution.py ├── chiron.py └── sbfl.py ├── .vs ├── ProjectSettings.json ├── slnx.sqlite ├── VSWorkspaceState.json └── Chiron-Framework │ ├── v17 │ └── .wsuo │ └── FileContentIndex │ └── 24eb9a46-759a-40b6-b227-e17abacfb467.vsidx ├── docs ├── paper.pdf ├── ChironLang-guide.pdf ├── FuzzingAssigment.pdf ├── CoverageGuidedFuzzing.md ├── AddRemoveIRInstructions.md ├── AddingNewCommand.md └── FuzzingAssigment.md ├── assets ├── Fuzzer_Demo.mp4 ├── example1_demo.zip ├── Architecture_Digram.png ├── AI_Chiron_danger_zone.png ├── AbstractInterpretation_Demo.mp4 ├── example1 │ ├── control_flow_graph.png │ ├── example1.tl │ └── example1.irbin └── Screenshot from 2025-01-16 12-34-51.png ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── bug_report.md │ └── bug_report_form.yaml ├── pull_request_template.md └── PULL_REQUEST_TEMPLATE │ ├── feature_addition_template.md │ └── bug_fix_template.md ├── LICENSE ├── Submission ├── testData.json ├── fuzzSubmission.py ├── symbSubmission.py ├── submissionAI.py ├── submissionDFA.py └── sbflSubmission.py ├── .gitignore └── README.md /ChironCore/cfg/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ChironCore/ChironAST/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ChironCore/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ChironCore/turtparse/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": null 3 | } -------------------------------------------------------------------------------- /docs/paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/docs/paper.pdf -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/.vs/slnx.sqlite -------------------------------------------------------------------------------- /.vs/VSWorkspaceState.json: -------------------------------------------------------------------------------- 1 | { 2 | "ExpandedNodes": [], 3 | "PreviewInSolutionExplorer": false 4 | } -------------------------------------------------------------------------------- /assets/Fuzzer_Demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/Fuzzer_Demo.mp4 -------------------------------------------------------------------------------- /assets/example1_demo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/example1_demo.zip -------------------------------------------------------------------------------- /docs/ChironLang-guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/docs/ChironLang-guide.pdf -------------------------------------------------------------------------------- /docs/FuzzingAssigment.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/docs/FuzzingAssigment.pdf -------------------------------------------------------------------------------- /ChironCore/example/exampleSE.tl: -------------------------------------------------------------------------------- 1 | :y = :x 2 | if :x <= 42 [ 3 | :y = :y + 40 4 | ] else [ 5 | :y = :y + 22 6 | ] 7 | -------------------------------------------------------------------------------- /.vs/Chiron-Framework/v17/.wsuo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/.vs/Chiron-Framework/v17/.wsuo -------------------------------------------------------------------------------- /ChironCore/example/kachuapur.tl: -------------------------------------------------------------------------------- 1 | :i = 0 2 | repeat 8 [ 3 | :i = 1 + :i 4 | right(90) 5 | forward(:delta * :i) 6 | ] 7 | -------------------------------------------------------------------------------- /assets/Architecture_Digram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/Architecture_Digram.png -------------------------------------------------------------------------------- /ChironCore/ChironHooks/tenor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/ChironCore/ChironHooks/tenor.gif -------------------------------------------------------------------------------- /assets/AI_Chiron_danger_zone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/AI_Chiron_danger_zone.png -------------------------------------------------------------------------------- /assets/AbstractInterpretation_Demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/AbstractInterpretation_Demo.mp4 -------------------------------------------------------------------------------- /assets/example1/control_flow_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/example1/control_flow_graph.png -------------------------------------------------------------------------------- /ChironCore/example/control_flow_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/ChironCore/example/control_flow_graph.png -------------------------------------------------------------------------------- /ChironCore/extlib/antlr-4.7.2-complete.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/ChironCore/extlib/antlr-4.7.2-complete.jar -------------------------------------------------------------------------------- /assets/Screenshot from 2025-01-16 12-34-51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/assets/Screenshot from 2025-01-16 12-34-51.png -------------------------------------------------------------------------------- /ChironCore/example/kachuapur2.tl: -------------------------------------------------------------------------------- 1 | :cnt = 0 2 | :i = 0 3 | repeat :steps [ 4 | :i = :cnt + :i 5 | :cnt = :cnt + 1 6 | forward(1 + :cnt) 7 | right(:radius) 8 | ] 9 | -------------------------------------------------------------------------------- /.vs/Chiron-Framework/FileContentIndex/24eb9a46-759a-40b6-b227-e17abacfb467.vsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PRAISE-group/Chiron-Framework/HEAD/.vs/Chiron-Framework/FileContentIndex/24eb9a46-759a-40b6-b227-e17abacfb467.vsidx -------------------------------------------------------------------------------- /ChironCore/example/example1.tl: -------------------------------------------------------------------------------- 1 | pendown 2 | 3 | repeat 3 [ 4 | 5 | if (:x > :y) [ 6 | penup 7 | goto (:x, :y) 8 | pendown 9 | repeat 4 [ 10 | forward :x 11 | left 90 12 | ] 13 | ] else [ 14 | penup 15 | goto (:y, :x) 16 | pendown 17 | repeat 5 [ 18 | forward :p 19 | left 72 20 | ] 21 | ] 22 | 23 | if (:z >= :p) [ 24 | penup 25 | goto (:p, :x + :z) 26 | pendown 27 | repeat 6 [ 28 | backward :x 29 | left 60 30 | ] 31 | ] 32 | 33 | :x = :x + 10 34 | :y = :y + 10 35 | :z = :z + 10 36 | ] 37 | 38 | penup -------------------------------------------------------------------------------- /assets/example1/example1.tl: -------------------------------------------------------------------------------- 1 | pendown 2 | 3 | repeat 3 [ 4 | 5 | if (:x > :y) [ 6 | penup 7 | goto (:x, :y) 8 | pendown 9 | repeat 4 [ 10 | forward :x 11 | left 90 12 | ] 13 | ] else [ 14 | penup 15 | goto (:y, :x) 16 | pendown 17 | repeat 5 [ 18 | forward :p 19 | left 72 20 | ] 21 | ] 22 | 23 | if (:z >= :p) [ 24 | penup 25 | goto (:p, :x + :z) 26 | pendown 27 | repeat 6 [ 28 | backward :x 29 | left 60 30 | ] 31 | ] 32 | 33 | :x = :x + 10 34 | :y = :y + 10 35 | :z = :z + 10 36 | ] 37 | 38 | penup -------------------------------------------------------------------------------- /docs/CoverageGuidedFuzzing.md: -------------------------------------------------------------------------------- 1 | ### Fuzzer for Chiron. (Needed for Assignment-4) 2 | 3 | A coverage guided `fuzzing` loop has been implemented in `ChironCore/fuzzer.py` file. 4 | 5 | Running the `Fuzzer` Loop : (From `ChironCore folder`) 6 | 7 | ```bash 8 | 9 | $ ./Chiron.py -t 100 --fuzz example/fuzz2.tl -d '{":x": 5, ":y": 100}' 10 | $ ./Chiron.py -t 100 --fuzz example/example2.tl -d '{":dir": 3, ":move": 5}' 11 | ``` 12 | 13 | Fuzzer specific arguments. 14 | 15 | ```js 16 | 17 | -t : Time budget for fuzzing in seconds. (optional) 18 | -d : Specify initial parameters. (required) 19 | --fuzz : Run fuzzing Loop 20 | ``` -------------------------------------------------------------------------------- /ChironCore/dataFlowAnalysis.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This file implements the worklist algorithm. 3 | WorkList class is the class for worklist queue 4 | and necessary functions to operate on the worklist. 5 | worklistAlgorithm actually implements the worklist algorithm. 6 | ''' 7 | 8 | from queue import Queue 9 | import sys 10 | import cfg.cfgBuilder as cfgB 11 | import cfg.ChironCFG as cfgK 12 | 13 | sys.path.insert(0, '../Submission/') 14 | from submissionDFA import * 15 | from abstractInterpretation import * 16 | 17 | class DataFlowAnalysis(AbstractInterpreter): 18 | def __init__(self, irHandler): 19 | super().__init__(irHandler) 20 | self.pc = 0 -------------------------------------------------------------------------------- /ChironCore/example/example2.tl: -------------------------------------------------------------------------------- 1 | penup 2 | goto (50, 50) 3 | pendown 4 | :two = 200 5 | :one = 100 6 | forward 50 7 | right 90 8 | forward 50 9 | right 90 10 | forward 50 11 | right 90 12 | forward 50 13 | penup 14 | 15 | :vara = 20 16 | :varb = 100 17 | :varc = 60 18 | repeat 1 [ 19 | goto (0, 0) 20 | pendown 21 | repeat 6 [ 22 | if (:vara != :varb) [ 23 | if ( :vara > :varb) [ right :vara ] 24 | else [ left :varb ] 25 | ] 26 | else [ 27 | if ((:vara <= :varc) || (:varb <= :varc)) [ 28 | :vara = :varc / :vara 29 | :varb = :varb / :varc 30 | :varc = :varb 31 | ] 32 | ] 33 | forward :vara 34 | right :varb 35 | forward :varc 36 | left :varc 37 | ] 38 | left 45 39 | ] 40 | penup -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /ChironCore/z3solver.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | class z3Solver(object): 4 | """docstring for z3Solver.""" 5 | 6 | def __init__(self): 7 | super(z3Solver, self).__init__() 8 | self.s = Solver() 9 | self.tmp = None 10 | 11 | def addSymbVar(self,var): 12 | exec("global %s; %s = Int(\"%s\")"%(var,var,var)) 13 | 14 | def addConstraint(self,constraint): 15 | exec("self.s.add(%s)"%(constraint)) 16 | 17 | def addAssignment(self,lhs,rhs): 18 | exec("global %s;%s=%s"%(lhs,lhs,rhs)) 19 | 20 | def assignSymbolicEncoding(self,exp): 21 | exec("self.tmp = %s"%(exp)) 22 | return self.tmp 23 | 24 | def getVar(self,var): 25 | _locals = locals() 26 | exec("exp = %s"%(var),globals(),_locals) 27 | exp = _locals['exp'] 28 | return exp 29 | -------------------------------------------------------------------------------- /ChironCore/turtparse/parseError.py: -------------------------------------------------------------------------------- 1 | class SyntaxException(Exception): 2 | def __init__(self, message, errors): 3 | # Call the base class constructor with the parameters it needs 4 | self.message=message 5 | self.errors = errors 6 | 7 | def __str__(self): 8 | return self.message + "\nLine : " + str(self.errors[0]) +\ 9 | ", Column : " + str(self.errors[1]) +\ 10 | "\nReport: (" + self.errors[2] + ")" 11 | 12 | class SyntaxErrorListener(): 13 | def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): 14 | raise SyntaxException("Syntax Error", (line, column, msg)) 15 | 16 | def reportAmbiguity(self): 17 | raise ValueError("Ambiguity error.") 18 | 19 | def reportContextSensitivity(self): 20 | raise ValueError("Exit due to context sensitivity.") 21 | -------------------------------------------------------------------------------- /ChironCore/turtparse/tlang.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | T__1=2 3 | T__2=3 4 | T__3=4 5 | T__4=5 6 | T__5=6 7 | T__6=7 8 | T__7=8 9 | T__8=9 10 | T__9=10 11 | T__10=11 12 | T__11=12 13 | T__12=13 14 | T__13=14 15 | T__14=15 16 | T__15=16 17 | T__16=17 18 | PLUS=18 19 | MINUS=19 20 | MUL=20 21 | DIV=21 22 | PENCOND=22 23 | LT=23 24 | GT=24 25 | EQ=25 26 | NEQ=26 27 | LTE=27 28 | GTE=28 29 | AND=29 30 | OR=30 31 | NOT=31 32 | NUM=32 33 | VAR=33 34 | NAME=34 35 | Whitespace=35 36 | 'if'=1 37 | '['=2 38 | ']'=3 39 | 'else'=4 40 | 'repeat'=5 41 | 'goto'=6 42 | '('=7 43 | ','=8 44 | ')'=9 45 | '='=10 46 | 'forward'=11 47 | 'backward'=12 48 | 'left'=13 49 | 'right'=14 50 | 'penup'=15 51 | 'pendown'=16 52 | 'pause'=17 53 | '+'=18 54 | '-'=19 55 | '*'=20 56 | '/'=21 57 | 'pendown?'=22 58 | '<'=23 59 | '>'=24 60 | '=='=25 61 | '!='=26 62 | '<='=27 63 | '>='=28 64 | '&&'=29 65 | '||'=30 66 | '!'=31 67 | -------------------------------------------------------------------------------- /ChironCore/turtparse/tlangLexer.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | T__1=2 3 | T__2=3 4 | T__3=4 5 | T__4=5 6 | T__5=6 7 | T__6=7 8 | T__7=8 9 | T__8=9 10 | T__9=10 11 | T__10=11 12 | T__11=12 13 | T__12=13 14 | T__13=14 15 | T__14=15 16 | T__15=16 17 | T__16=17 18 | PLUS=18 19 | MINUS=19 20 | MUL=20 21 | DIV=21 22 | PENCOND=22 23 | LT=23 24 | GT=24 25 | EQ=25 26 | NEQ=26 27 | LTE=27 28 | GTE=28 29 | AND=29 30 | OR=30 31 | NOT=31 32 | NUM=32 33 | VAR=33 34 | NAME=34 35 | Whitespace=35 36 | 'if'=1 37 | '['=2 38 | ']'=3 39 | 'else'=4 40 | 'repeat'=5 41 | 'goto'=6 42 | '('=7 43 | ','=8 44 | ')'=9 45 | '='=10 46 | 'forward'=11 47 | 'backward'=12 48 | 'left'=13 49 | 'right'=14 50 | 'penup'=15 51 | 'pendown'=16 52 | 'pause'=17 53 | '+'=18 54 | '-'=19 55 | '*'=20 56 | '/'=21 57 | 'pendown?'=22 58 | '<'=23 59 | '>'=24 60 | '=='=25 61 | '!='=26 62 | '<='=27 63 | '>='=28 64 | '&&'=29 65 | '||'=30 66 | '!'=31 67 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Pull Request Template for Feature Additions. 2 | 3 | ## Brief description feature 4 | 5 | Provide the details of the feature, explain it's functionality. 6 | 7 | ```c 8 | 9 | ``` 10 | 11 | ## Example 12 | 13 | Give a test case and related commands that show the utility of the feature. 14 | 15 | ```c 16 | 17 | ``` 18 | 19 | Please add a atleast 3 test cases to the repository which shows how the feature works and what are the outcomes. 20 | 21 | ```c 22 | # test 23 | 24 | ``` 25 | 26 | ### Why is the feature interesting? 27 | 28 | Give use cases for the feature. 29 | 30 | ```c 31 | 32 | ``` 33 | 34 | ## Screenshots 35 | 36 | Please add screenshots whenever possible. 37 | 38 | ## Other Details 39 | 40 | Please add additional details that you want the developers to be aware of about the feature. Eg. good use cases (if any). 41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/feature_addition_template.md: -------------------------------------------------------------------------------- 1 | # Pull Request Template for Feature Additions. 2 | 3 | ## Brief description feature 4 | 5 | Provide the details of the feature, explain it's functionality. 6 | 7 | ```c 8 | 9 | ``` 10 | 11 | ## Example 12 | 13 | Give a test case and related commands that show the utility of the feature. 14 | 15 | ```c 16 | 17 | ``` 18 | 19 | Please add a atleast 3 test cases to the repository which shows how the feature works and what are the outcomes. 20 | 21 | ```c 22 | # test 23 | 24 | ``` 25 | 26 | ### Why is the feature interesting? 27 | 28 | Give use cases for the feature. 29 | 30 | ```c 31 | 32 | ``` 33 | 34 | ## Screenshots 35 | 36 | Please add screenshots whenever possible. 37 | 38 | ## Other Details 39 | 40 | Please add additional details that you want the developers to be aware of about the feature. Eg. good use cases (if any). 41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/bug_fix_template.md: -------------------------------------------------------------------------------- 1 | # Pull Request Template for Bug Fixes. 2 | 3 | ## Brief description of the bug. 4 | Provide the details of the bug fixed. 5 | 6 | ```c 7 | 8 | ``` 9 | 10 | ## Example 11 | 12 | Give a test case and commands that triggered the bug. 13 | 14 | ```c 15 | 16 | ``` 17 | 18 | Please add a test case which demonstrates that the bug has been fixed. 19 | 20 | ```c 21 | # test 22 | 23 | ``` 24 | 25 | ## Expected Output 26 | 27 | ```c 28 | ``` 29 | 30 | ## Screenshots 31 | 32 | Please add screenshots whenever possible. Please the terminal output/logs if available. 33 | 34 | ## Other Details 35 | 36 | Please add additional details that you want the developers to be aware of about the bug. Eg. side-effects. 37 | 38 | 39 | ## Environment 40 | 41 | Give details about the environment where Chiron was run. 42 | 43 | ```python 44 | OS: Linux 45 | Python: 3.10.2 46 | Kernel: 6.5.3 47 | Docker: Yes/No 48 | ``` 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /ChironCore/lattice.py: -------------------------------------------------------------------------------- 1 | class Lattice(): 2 | ''' 3 | Base class for the abstract values 4 | ''' 5 | '''Initialize abstract value''' 6 | 7 | def __init__(self, data): 8 | pass 9 | 10 | '''To display abstract values''' 11 | 12 | def __str__(self): 13 | pass 14 | 15 | '''To check whether abstract value is bot or not''' 16 | 17 | def isBot(self): 18 | pass 19 | 20 | '''To check whether abstract value is Top or not''' 21 | 22 | def isTop(self): 23 | pass 24 | 25 | '''Implement the meet operator''' 26 | 27 | def meet(self, other): 28 | pass 29 | 30 | '''Implement the join operator''' 31 | 32 | def join(self, other): 33 | pass 34 | 35 | '''partial order with the other lattice value''' 36 | def __le__(self, other): 37 | pass 38 | 39 | '''equality check with other lattice value''' 40 | def __eq__(self, other): 41 | pass 42 | 43 | ''' 44 | Add here for other operations 45 | ''' 46 | 47 | class TransferFunction(): 48 | def __init__(self): 49 | pass -------------------------------------------------------------------------------- /docs/AddRemoveIRInstructions.md: -------------------------------------------------------------------------------- 1 | ## Addition/Removal of Instructions from IR. 2 | 3 | Two new functions have been added in `irgen.py` to add and remove statements from a given IR List. 4 | 5 | ## `addInstruction(IRList, Inst, pos)` 6 | 7 | Given a list of IR Statements (`IRList`), IR instruction statement of `ChironAST` type and a position `pos` (postiton to insert an IR statement), 8 | the function inserts the statement in `IRList`. Conditional Statements cannot be added. Relative jumps of all the affected statements are updated. 9 | 10 | ## `removeInstruction(IRList, pos)` 11 | 12 | Given a list of IR Statements (`IRList`) and a position `pos` (postiton to delete an IR statement from `IRList`), 13 | removeInstruction() converts the statement into a no-op, effectively removing it from the IR list, 14 | The `NOP` functionality for interpreter has also been added in `interpreter.py`. 15 | 16 | ### Usage : 17 | 18 | ```python3 19 | addInstruction(ir, ChironAST.AssignmentCommand(ChironAST.Var(":vara"), ChironAST.Num(5)), 11) 20 | # 11 :vara = 5 [ 1 ] 21 | 22 | removeInstruction(ir, 11) 23 | # 11 : NOP [ 1 ] 24 | ``` 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Subhajit Roy, Prantik Chaterjee, Gourav Takhar, Sujit Muduli, Pankaj Kalita, Sumit Lahiri, Vishal Singh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /ChironCore/interfaces/fuzzerInterface.py: -------------------------------------------------------------------------------- 1 | class MutatorBase(): 2 | # Base class to extend/implement a 3 | # custom mutation operator. 4 | def __init__(self): 5 | pass 6 | 7 | def mutate(self, input_data, coverageInfo, irList): 8 | # must return InputObject type 9 | # coverageInfo is of type CoverageMetricBase 10 | # irList : List of IR Statments (Don't Modify) 11 | # Don't mutate coverageInfo 12 | pass 13 | 14 | def operate(self, input_data, operatorFunc): 15 | # must return InputObject type 16 | pass 17 | 18 | class CoverageMetricBase(): 19 | # Base class to extend/implement a 20 | # custom coverage metric. 21 | def __init__(self): 22 | # Must have curr_metric, total_metric 23 | self.curr_metric = [] 24 | self.total_metric = [] 25 | 26 | 27 | def compareCoverage(self, curr_metric, total_metric): 28 | # must compare curr_metric and total_metric 29 | # Return True/False based on increase in coverage. 30 | return False 31 | 32 | def updateTotalCoverage(self, curr_metric, total_metric): 33 | # Compute the total_metric coverage and return it (list) 34 | # this changes if new coverage is seen for a 35 | # given input. 36 | return total_metric -------------------------------------------------------------------------------- /assets/example1/example1.irbin: -------------------------------------------------------------------------------- 1 | ========== Chiron IR ========== 2 | 3 | The first label before the opcode name represents the IR index or label 4 | on the control flow graph for that node. 5 | 6 | The number after the opcode name represents the jump offset 7 | relative to that statement. 8 | 9 | [L0] pendown [1] 10 | [L1] :__rep_counter_1 = 3 [1] 11 | [L2] (:__rep_counter_1 != 0) [36] 12 | [L3] (:x > :y) [11] 13 | [L4] penup [1] 14 | [L5] goto :x :y [1] 15 | [L6] pendown [1] 16 | [L7] :__rep_counter_2 = 4 [1] 17 | [L8] (:__rep_counter_2 != 0) [5] 18 | [L9] forward :x [1] 19 | [L10] left 90 [1] 20 | [L11] :__rep_counter_2 = (:__rep_counter_2 - 1) [1] 21 | [L12] False [-4] 22 | [L13] False [10] 23 | [L14] penup [1] 24 | [L15] goto :y :x [1] 25 | [L16] pendown [1] 26 | [L17] :__rep_counter_3 = 5 [1] 27 | [L18] (:__rep_counter_3 != 0) [5] 28 | [L19] forward :p [1] 29 | [L20] left 72 [1] 30 | [L21] :__rep_counter_3 = (:__rep_counter_3 - 1) [1] 31 | [L22] False [-4] 32 | [L23] (:z >= :p) [10] 33 | [L24] penup [1] 34 | [L25] goto :p (:x + :z) [1] 35 | [L26] pendown [1] 36 | [L27] :__rep_counter_4 = 6 [1] 37 | [L28] (:__rep_counter_4 != 0) [5] 38 | [L29] backward :x [1] 39 | [L30] left 60 [1] 40 | [L31] :__rep_counter_4 = (:__rep_counter_4 - 1) [1] 41 | [L32] False [-4] 42 | [L33] :x = (:x + 10) [1] 43 | [L34] :y = (:y + 10) [1] 44 | [L35] :z = (:z + 10) [1] 45 | [L36] :__rep_counter_1 = (:__rep_counter_1 - 1) [1] 46 | [L37] False [-35] 47 | [L38] penup [1] 48 | 49 | -------------------------------------------------------------------------------- /Submission/testData.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "params": "{'radius': 0}", 4 | "constparams": "[]", 5 | "coverage": "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3, 4, 5, 6, 7, 8, 9, 3]", 6 | "pc": "[3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3]", 7 | "pcEval": "[True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, True, False, False]", 8 | "symbEnc": "{'radius': 'radius', 'cnt': '22', 'i': '231', '__rep_counter_1': '0'}", 9 | "constraints": "[True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n True,\n Not(False),\n Not(False)]" 10 | } 11 | } -------------------------------------------------------------------------------- /ChironCore/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Subhajit Roy, Sujit Kumar Muduli, Pankaj Kumar Kalita, Gourav Takhar, Sumit Lahiri, Prantik Chatterjee 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Submission/fuzzSubmission.py: -------------------------------------------------------------------------------- 1 | from ChironAST import ChironAST 2 | import sys 3 | from z3 import * 4 | import random 5 | sys.path.insert(0, "ChironCore/interfaces/") 6 | from interfaces.fuzzerInterface import * 7 | sys.path.insert(0, '../ChironCore/') 8 | 9 | # Each input is of this type. 10 | # class InputObject(): 11 | # def __init__(self, data): 12 | # self.id = str(uuid.uuid4()) 13 | # self.data = data 14 | # # Flag to check if ever picked 15 | # # for mutation or not. 16 | # self.pickedOnce = False 17 | 18 | class CustomCoverageMetric(CoverageMetricBase): 19 | # Statements covered is used for 20 | # coverage information. 21 | def __init__(self): 22 | super().__init__() 23 | 24 | # TODO : Implement this 25 | def compareCoverage(self, curr_metric, total_metric): 26 | # must compare curr_metric and total_metric 27 | # True if Improved Coverage else False 28 | return True 29 | 30 | # TODO : Implement this 31 | def updateTotalCoverage(self, curr_metric, total_metric): 32 | # Compute the total_metric coverage and return it (list) 33 | # this changes if new coverage is seen for a 34 | # given input. 35 | return total_metric 36 | 37 | class CustomMutator(MutatorBase): 38 | def __init__(self): 39 | pass 40 | 41 | # TODO : Implement this 42 | def mutate(self, input_data, coverageInfo, irList): 43 | # Mutate the input data and return it 44 | # coverageInfo is of type CoverageMetricBase 45 | # Don't mutate coverageInfo 46 | # irList : List of IR Statments (Don't Modify) 47 | # input_data.data -> type dict() with {key : variable(str), value : int} 48 | # must return input_data after mutation. 49 | return input_data 50 | 51 | 52 | # Reuse code and imports from 53 | # earlier submissions (if any). 54 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_form.yaml: -------------------------------------------------------------------------------- 1 | name: "Bug Report Form" 2 | description: You can submit this form instead of a .md (that easier!) 3 | title: "[Bug]: " 4 | labels: ["bug", "triage"] 5 | assignees: 6 | - lahiri-phdworks 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report! 12 | - type: input 13 | id: contact 14 | attributes: 15 | label: Contact Details 16 | description: How can we get in touch with you if we need more info? 17 | placeholder: ex. email@example.com 18 | validations: 19 | required: false 20 | - type: textarea 21 | id: what-happened 22 | attributes: 23 | label: What happened? 24 | description: Also tell us, what did you expect to happen? 25 | placeholder: Tell us what you see! 26 | value: "A bug happened!" 27 | validations: 28 | required: true 29 | - type: dropdown 30 | id: version 31 | attributes: 32 | label: Version 33 | description: What version of our software are you running? 34 | options: 35 | - 1.0.2 (Default) 36 | - 1.0.3 (Edge) 37 | default: 0 38 | validations: 39 | required: true 40 | - type: dropdown 41 | id: browsers 42 | attributes: 43 | label: What browsers are you seeing the problem on? 44 | multiple: true 45 | options: 46 | - Firefox 47 | - Chrome 48 | - Safari 49 | - Microsoft Edge 50 | - type: textarea 51 | id: logs 52 | attributes: 53 | label: Relevant log output 54 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 55 | render: shell 56 | - type: checkboxes 57 | id: terms 58 | attributes: 59 | label: Code of Conduct 60 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://en.wikipedia.org/wiki/Code_of_conduct) 61 | options: 62 | - label: I agree to follow this project's Code of Conduct 63 | required: true 64 | -------------------------------------------------------------------------------- /ChironCore/turtparse/tlang.g4: -------------------------------------------------------------------------------- 1 | 2 | grammar tlang; 3 | 4 | start : instruction_list EOF 5 | ; 6 | 7 | instruction_list : (instruction)* 8 | ; 9 | 10 | strict_ilist : (instruction)+ 11 | ; 12 | 13 | instruction : assignment 14 | | conditional 15 | | loop 16 | | moveCommand 17 | | penCommand 18 | | gotoCommand 19 | | pauseCommand 20 | ; 21 | 22 | conditional : ifConditional | ifElseConditional ; 23 | 24 | ifConditional : 'if' condition '[' strict_ilist ']' ; 25 | 26 | ifElseConditional : 'if' condition '[' strict_ilist ']' 'else' '[' strict_ilist ']' ; 27 | 28 | loop : 'repeat' value '[' strict_ilist ']' ; 29 | 30 | gotoCommand : 'goto' '(' expression ',' expression ')'; 31 | 32 | assignment : VAR '=' expression 33 | ; 34 | 35 | moveCommand : moveOp expression ; 36 | moveOp : 'forward' | 'backward' | 'left' | 'right' ; 37 | 38 | penCommand : 'penup' | 'pendown' ; 39 | 40 | pauseCommand : 'pause' ; 41 | 42 | expression : 43 | unaryArithOp expression #unaryExpr 44 | | expression multiplicative expression #mulExpr 45 | | expression additive expression #addExpr 46 | | value #valueExpr 47 | | '(' expression ')' #parenExpr 48 | ; 49 | 50 | multiplicative : MUL | DIV; 51 | additive : PLUS | MINUS; 52 | 53 | unaryArithOp : MINUS ; 54 | 55 | PLUS : '+' ; 56 | MINUS : '-' ; 57 | MUL : '*' ; 58 | DIV : '/' ; 59 | 60 | 61 | // TODO : 62 | // procedure_declaration : 'to' NAME (VAR)+ strict_ilist 'end' ; 63 | 64 | condition : NOT condition 65 | |expression binCondOp expression 66 | | condition logicOp condition 67 | | PENCOND 68 | | '(' condition ')' 69 | ; 70 | 71 | 72 | binCondOp : EQ | NEQ | LT | GT | LTE | GTE 73 | ; 74 | 75 | logicOp : AND | OR ; 76 | 77 | PENCOND : 'pendown?'; 78 | LT : '<' ; 79 | GT : '>' ; 80 | EQ : '=='; 81 | NEQ: '!='; 82 | LTE: '<='; 83 | GTE: '>='; 84 | AND: '&&'; 85 | OR : '||'; 86 | NOT: '!' ; 87 | 88 | value : NUM 89 | | VAR 90 | ; 91 | 92 | NUM : [0-9]+ ; 93 | 94 | VAR : ':'[a-zA-Z_] [a-zA-Z0-9]* ; 95 | 96 | NAME : [a-zA-Z]+ ; 97 | 98 | Whitespace: [ \t\n\r]+ -> skip; 99 | -------------------------------------------------------------------------------- /docs/AddingNewCommand.md: -------------------------------------------------------------------------------- 1 | This explains a simple example of adding `goto` command in Chiron language. However adding any new command should follow these steps only. 2 | 3 | **1. Adding new grammar rule in `tlang.g4`** 4 | 5 | - The grammar rules are defined in `ChironCore/parser/tlang.g4` 6 | 7 | - Since we are adding a new Command/Instruction. we should add it under the `instruction` rule in the grammar. 8 | 9 | - ```antlr4 10 | instruction : assignment 11 | | conditional 12 | | loop 13 | | moveCommand 14 | | penCommand 15 | | gotoCommand // <--- new command added ---> 16 | ; 17 | 18 | gotoCommand : 'goto' '(' expression ',' expression ')'; // <--- goto command rule ---> 19 | ``` 20 | 21 | - Next step, is to regenerate antlr4 parser code. Execute the following command from `parser` directory. 22 | 23 | - ```bash 24 | java -cp ../extlib/antlr-4.7.2-complete.jar org.antlr.v4.Tool -Dlanguage=Python3 -visitor -no-listener tlang.g4 25 | ``` 26 | 27 | 28 | 29 | **2. Create a python class for `goto` command in `ChironCore/ast/ChironAST.py`** 30 | 31 | - ```python 32 | class GotoCommand(Instruction): 33 | def __init__(self, x, y): 34 | self.xcor = x 35 | self.ycor = y 36 | 37 | def __str__(self): 38 | return "goto " + str(self.xcor) + " " + str(self.ycor) 39 | ``` 40 | 41 | - You must implement `__str__` , this is used by IR pretty print and sometimes by Chiron interpreter. 42 | 43 | 44 | 45 | **3. Adding visitor for the new parse tree nodes** 46 | 47 | - antlr4 generates visitors for parse tree nodes which we can override to create corresponding objects in the `ChironAST.py` 48 | 49 | - The file `ChironCore/parser/tlangVisitor.py` has a base visitor class which is inherited by `astGenPass` in `ChironCore/ast/builder.py` 50 | 51 | - For our implementation we need to override `visitGotoCommand` in `ChironCore/parser/tlangVisitor.py`. Following is the visitor definition we want to add to `astGenPass` in `ChironCore/ast/builder.py`. This will create a `ChironAST.GotoCommand` object which will be added to the IR. 52 | 53 | - ```python 54 | def visitGotoCommand(self, ctx: tlangParser.GotoCommandContext): 55 | xcor = self.visit(ctx.expression(0)) 56 | ycor = self.visit(ctx.expression(1)) 57 | return [(ChironAST.GotoCommand(xcor, ycor), 1)] 58 | ``` 59 | - Ref. https://sourcemaking.com/design_patterns/visitor to understand the visitor design pattern 60 | -------------------------------------------------------------------------------- /ChironCore/cfg/ChironCFG.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3.8 2 | 3 | import networkx as nx 4 | 5 | class BasicBlock: 6 | def __init__(self, bbname): 7 | self.name = bbname 8 | self.instrlist = [] 9 | if bbname == "START" or bbname == "END": 10 | self.irID = bbname 11 | else: 12 | self.irID = int(bbname) - 1 13 | 14 | def __str__(self): 15 | return self.name 16 | 17 | def append(self, instruction): 18 | self.instrlist.append(instruction) 19 | 20 | def extend(self, instructions): 21 | self.instrlist.extend(instructions) 22 | 23 | def label(self): 24 | if len(self.instrlist): 25 | return '\n'.join(str(instr[0])+'; L'+ str(instr[1]) for instr in self.instrlist) 26 | else: 27 | return self.name 28 | 29 | 30 | class ChironCFG: 31 | 32 | """ 33 | An adapter for Networkx.DiGraph. 34 | """ 35 | 36 | def __init__(self, gname='cfg'): 37 | self.name = gname 38 | self.nxgraph = nx.DiGraph(name=gname) 39 | self.entry = "0" 40 | self.exit = "END" 41 | 42 | def __iter__(self): 43 | return self.nxgraph.__iter__() 44 | 45 | def is_directed(self): 46 | return True 47 | 48 | def add_node(self, node): 49 | if not isinstance(node, BasicBlock): 50 | raise ValueError("wrong type for 'node' parameter") 51 | 52 | self.nxgraph.add_node(node) 53 | 54 | def has_node(self, node): 55 | return self.nxgraph.has_node(node) 56 | 57 | def add_edge(self, u, v, **attr): 58 | if self.has_node(u): 59 | if self.has_node(v): 60 | self.nxgraph.add_edge(u, v, **attr) 61 | else: 62 | # TODO: do appropriate error reporting 63 | raise NameError(v) 64 | else: 65 | raise NameError(u) 66 | 67 | def nodes(self): 68 | return self.nxgraph.nodes() 69 | 70 | def edges(self): 71 | return self.nxgraph.edges() 72 | 73 | def successors(self, node): 74 | return self.nxgraph.successors(node) 75 | 76 | def predecessors(self, node): 77 | return self.nxgraph.predecessors(node) 78 | 79 | def out_degree(self, node): 80 | return self.nxgraph.out_degree(node) 81 | 82 | def in_degree(self, node): 83 | return self.nxgraph.in_degree(node) 84 | 85 | def get_edge_label(self, u, v): 86 | edata = self.nxgraph.get_edge_data(u,v) 87 | return edata['label'] if len(edata) else 'T' 88 | 89 | # TODO: add more methods to expose other methods of the Networkx.DiGraph 90 | -------------------------------------------------------------------------------- /ChironCore/ChironHooks/Chironhooks.py: -------------------------------------------------------------------------------- 1 | # Abstract Class. 2 | class ChironHooks: 3 | params = None 4 | 5 | def __init__(self): 6 | pass 7 | 8 | def ChironStartHook(self, interpreterObj): 9 | pass 10 | 11 | def ChironEndHook(self, interpreterObj): 12 | pass 13 | 14 | 15 | class ConcreteChironHooks(ChironHooks): 16 | 17 | def __init__(self): 18 | # rest of the initialization code. 19 | pass 20 | 21 | # Override 22 | def ChironStartHook(self, interpreterObj): 23 | # What happens when interpreter starts. 24 | #print(f"\n\n[Chiron] Interpreter is starting, PC ->{interpreterObj.trtl.pos()}.\n\n") 25 | #print(f"\n\n[Chiron] Interpreter is starting, PC ->{interpreterObj.trtl.speed()}.\n\n") 26 | 27 | tur = interpreterObj.trtl 28 | tur.hideturtle() 29 | tur.speed(100) 30 | curr_color = tur.color() 31 | tur.color(curr_color[0],'yellow') 32 | tur.begin_fill() 33 | tur.penup() 34 | tur.goto(250, 200) 35 | tur.pendown() 36 | tur.goto(250, 300) 37 | tur.goto(300, 350) 38 | tur.goto(350, 300) 39 | tur.goto(350, 200) 40 | tur.goto(250, 200) 41 | tur.end_fill() 42 | tur.penup() 43 | 44 | tur.goto(170,200) 45 | tur.write("(250, 200)",font=("Verdana", 10, "bold")) 46 | tur.goto(170,300) 47 | tur.write("(250, 300)",font=("Verdana", 10, "bold")) 48 | tur.goto(270,360) 49 | tur.write("(300, 350)",font=("Verdana", 10, "bold")) 50 | tur.goto(370,300) 51 | tur.write("(350, 300)",font=("Verdana", 10, "bold")) 52 | tur.goto(370,200) 53 | tur.write("(350, 200)",font=("Verdana", 10, "bold")) 54 | tur.goto(260, 175) 55 | tur.write("Kachuapur",font=("Arial", 10, "bold")) 56 | 57 | tur.goto(0,0) 58 | tur.pendown() 59 | tur.speed(1) 60 | tur.color(*curr_color) 61 | tur.showturtle() 62 | 63 | # Override 64 | def ChironEndHook(self, interpreterObj): 65 | # What happens when interpreter ends. 66 | #print(f"\n\n[Chiron] Interpreter is ending, PC -> {interpreterObj.trtl.pos()}.\n\n") 67 | pos = interpreterObj.trtl.pos() 68 | x = pos[0] 69 | y = pos[1] 70 | if (100 * x - 35000 <= 0): 71 | if (100 * y - 20000 >= 0): 72 | if (-100 * x + 25000 <= 0): 73 | if (50 * x - 50 * y + 2500>=0): 74 | if (50 * x + 50 * y - 32500 <= 0): 75 | interpreterObj.t_screen.bgpic('./ChironHooks/tenor.gif') 76 | 77 | -------------------------------------------------------------------------------- /Submission/symbSubmission.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | import argparse 3 | import json 4 | import sys 5 | 6 | sys.path.insert(0, "../ChironCore/") 7 | 8 | from interfaces.sExecutionInterface import * 9 | from ChironAST.builder import astGenPass 10 | import z3solver as zs 11 | from irhandler import * 12 | from interpreter import * 13 | import ast 14 | 15 | # This is an example program showing the use 16 | # of Z3 Solver in python. 17 | def example(s): 18 | # To add symbolic variable x to solver 19 | s.addSymbVar("x") 20 | s.addSymbVar("y") 21 | # To add constraint in form of string 22 | s.addConstraint("x==5+y") 23 | s.addConstraint("And(x==y,x>5)") 24 | # s.addConstraint('Implies(x==4,y==x+8') 25 | # To access solvers directly use s.s.() 26 | print("constraints added till now", s.s.assertions()) 27 | # To assign z=x+y 28 | s.addAssignment("z", "x+y") 29 | # To get any variable assigned 30 | print("variable assignment of z =", s.getVar("z")) 31 | 32 | # IMPLEMENT THIS 33 | # FEEL FREE TO MODIFIY THIS CODE. 34 | def checkEq(args, ir): 35 | file1 = open("testData.json", "r+") 36 | testData = json.loads(file1.read()) 37 | file1.close() 38 | 39 | solver = zs.z3Solver() 40 | testData = convertTestData(testData) 41 | 42 | # to see what test data has been read. 43 | # print(testData) 44 | 45 | # This is the data read from the "-e" flag 46 | output = args.output 47 | # example(s) 48 | # TODO: write code to check equivalence 49 | 50 | 51 | if __name__ == "__main__": 52 | # you are free to add your own arguments and use them 53 | # in the functions of this file. 54 | cmdparser = argparse.ArgumentParser( 55 | description="symbSubmission for assignment Program Synthesis using Symbolic Execution" 56 | ) 57 | cmdparser.add_argument("progfl") 58 | cmdparser.add_argument("-b", "--bin", action="store_true", help="load binary IR") 59 | cmdparser.add_argument( 60 | "-e", 61 | "--output", 62 | default=list(), 63 | type=ast.literal_eval, 64 | help="pass variables to Chiron program in python dictionary format", 65 | ) 66 | # This object is use to store and pass the ir around. 67 | irHandler2 = IRHandler(None) 68 | args = cmdparser.parse_args() 69 | 70 | # generate IR of the program given 71 | # or load it from .kw file. 72 | if args.bin: 73 | ir = irHandler2.loadIR(args.progfl) 74 | else: 75 | parseTree = getParseTree(args.progfl) 76 | astgen = astGenPass() 77 | ir = astgen.visitStart(parseTree) 78 | 79 | irHandler2.pretty_print(irHandler2.ir) 80 | 81 | checkEq(args, ir) 82 | exit() 83 | -------------------------------------------------------------------------------- /Submission/submissionAI.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import math 3 | import sys 4 | from typing import overload 5 | 6 | sys.path.insert(0, "../ChironCore/") 7 | 8 | import cfg.ChironCFG as cfgK 9 | import cfg.cfgBuilder as cfgB 10 | from lattice import * 11 | import ChironAST.ChironAST as ChironAST 12 | import abstractInterpretation as AI 13 | 14 | ''' 15 | Class for interval domain 16 | ''' 17 | class IntervalDomain(Lattice): 18 | 19 | '''Initialize abstract value''' 20 | def __init__(self, data): 21 | pass 22 | 23 | '''To display abstract values''' 24 | def __str__(self): 25 | pass 26 | 27 | '''To check whether abstract value is bot or not''' 28 | def isBot(self): 29 | pass 30 | 31 | '''To check whether abstract value is Top or not''' 32 | def isTop(self): 33 | pass 34 | 35 | '''Implement the meet operator''' 36 | def meet(self, other): 37 | pass 38 | 39 | '''Implement the join operator''' 40 | def join(self, other): 41 | pass 42 | 43 | '''partial order with the other abstract value''' 44 | def __le__(self, other): 45 | pass 46 | 47 | '''equality check with other abstract value''' 48 | def __eq__(self, other): 49 | pass 50 | 51 | ''' 52 | Add here required abstract transformers 53 | ''' 54 | pass 55 | 56 | class IntervalTransferFunction(TransferFunction): 57 | def __init__(self): 58 | pass 59 | 60 | def transferFunction(self, currBBIN, currBB): 61 | ''' 62 | Transfer function for basic block 'currBB' 63 | args: In val for currBB, currBB 64 | Returns newly calculated values in a form of list 65 | 66 | This is the transfer function you write for Abstract Interpretation. 67 | ''' 68 | #implement your transfer function here 69 | outVal = [] 70 | return outVal 71 | 72 | class ForwardAnalysis(): 73 | def __init__(self): 74 | self.transferFunctionInstance = IntervalTransferFunction() 75 | self.type = "IntervalTF" 76 | 77 | ''' 78 | This function is to initialize in of the basic block currBB 79 | Returns a dictinary {varName -> abstractValues} 80 | isStartNode is a flag for stating whether currBB is start basic block or not 81 | ''' 82 | def initialize(self, currBB, isStartNode): 83 | val = {} 84 | #Your additional initialisation code if any 85 | return val 86 | 87 | #just a dummy equallity check function for dictionary 88 | def isEqual(self, dA, dB): 89 | for i in dA.keys(): 90 | if i not in dB.keys(): 91 | return False 92 | if dA[i] != dB[i]: 93 | return False 94 | return True 95 | 96 | ''' 97 | Define the meet operation 98 | Returns a dictinary {varName -> abstractValues} 99 | ''' 100 | def meet(self, predList): 101 | assert isinstance(predList, list) 102 | meetVal = {} 103 | 104 | return meetVal 105 | 106 | def analyzeUsingAI(irHandler): 107 | ''' 108 | get the cfg outof IR 109 | each basic block consists of single statement 110 | ''' 111 | # call worklist and get the in/out values of each basic block 112 | abstractInterpreter = AI.AbstractInterpreter(irHandler) 113 | bbIn, bbOut = abstractInterpreter.worklistAlgorithm(irHandler.cfg) 114 | 115 | #implement your analysis according to the questions on each basic blocks 116 | pass 117 | -------------------------------------------------------------------------------- /Submission/submissionDFA.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import math 3 | import sys 4 | from typing import overload 5 | 6 | sys.path.insert(0, "../ChironCore/") 7 | 8 | import cfg.ChironCFG as cfgK 9 | import cfg.cfgBuilder as cfgB 10 | from lattice import * 11 | import ChironAST.ChironAST as ChironAST 12 | import dataFlowAnalysis as DFA 13 | 14 | 15 | ''' 16 | Class to work with lattice elements. 17 | Implement these functions as required. 18 | ''' 19 | class MovementDomain(Lattice): 20 | 21 | '''Initialize lattice value''' 22 | def __init__(self, data): 23 | pass 24 | 25 | '''To display lattice values''' 26 | def __str__(self): 27 | pass 28 | 29 | '''To check whether lattice value is bot or not''' 30 | def isBot(self): 31 | pass 32 | 33 | '''To check whether lattice value is Top or not''' 34 | def isTop(self): 35 | pass 36 | 37 | '''Implement the meet operator''' 38 | def meet(self, other): 39 | pass 40 | 41 | '''Implement the join operator''' 42 | def join(self, other): 43 | pass 44 | 45 | '''partial order with the other lattice value''' 46 | def __le__(self, other): 47 | pass 48 | 49 | '''equality check with other lattice value''' 50 | def __eq__(self, other): 51 | pass 52 | 53 | ''' 54 | Add here required lattice operations 55 | ''' 56 | pass 57 | 58 | 59 | class MovementTransferFunction(TransferFunction): 60 | def __init__(self): 61 | pass 62 | 63 | def transferFunction(self, currBBIN, currBB): 64 | ''' 65 | Transfer function for basic block 'currBB' 66 | args: In val for currBB, currBB 67 | Returns newly calculated values in a form of list 68 | 69 | This is the transfer function you write for DataFlow Analysis. 70 | ''' 71 | #implement your transfer function here 72 | outVal = [] 73 | return outVal 74 | 75 | class ForwardAnalysis(): 76 | def __init__(self): 77 | self.transferFunctionInstance = MovementTransferFunction() 78 | self.type = "MoveTF" 79 | 80 | ''' 81 | This function is to initialize in of the basic block currBB 82 | Returns a dictionary of {varName -> MovementDomain values} 83 | isStartNode is a flag for stating whether currBB is start basic block or not 84 | ''' 85 | def initialize(self, currBB, isStartNode): 86 | val = {} 87 | #Your additional initialisation code if any 88 | return val 89 | 90 | # just a dummy equallity check function for dictionary 91 | def isEqual(self, dA, dB): 92 | for i in dA.keys(): 93 | if i not in dB.keys(): 94 | return False 95 | if dA[i] != dB[i]: 96 | return False 97 | return True 98 | 99 | ''' 100 | Define the meet operation. 101 | Implement this function as required. 102 | Returns a dictionary of {varName -> MovementDomain values} 103 | ''' 104 | def meet(self, predList): 105 | assert isinstance(predList, list) 106 | meetVal = {} 107 | 108 | return meetVal 109 | 110 | def optimizeUsingDFA(irHandler): 111 | ''' 112 | get the cfg out of IR 113 | each basic block consists of single statement 114 | ''' 115 | # call worklist and get the in/out values of each basic block 116 | dfaIntrp = DFA.DataFlowAnalysis(irHandler) 117 | bbIn, bbOut = dfaIntrp.worklistAlgorithm(irHandler.cfg) 118 | 119 | 120 | # NOTE: Implement your code below. Do not change anything above this line. 121 | # Implement your analysis according to the questions on each basic block 122 | 123 | 124 | 125 | # TODO: Return the optimized IR in optIR 126 | optIR = irHandler.ir 127 | return optIR 128 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | 163 | # Extra files and hidden folder. 164 | testcases/ 165 | build/ -------------------------------------------------------------------------------- /ChironCore/cfg/cfgBuilder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import sys 4 | #sys.path.insert(0, '../ChironAST/') 5 | 6 | from cfg.ChironCFG import * 7 | import ChironAST.ChironAST as ChironAST 8 | 9 | import networkx as nx 10 | from networkx.drawing.nx_agraph import to_agraph 11 | 12 | # from graphviz import Source 13 | # import pydot 14 | 15 | # import matplotlib 16 | # import matplotlib.pyplot as plt 17 | # matplotlib.use('TkAgg') 18 | 19 | 20 | def buildCFG(ir, cfgName="", isSingle=False): 21 | 22 | startBB = BasicBlock('START') 23 | endBB = BasicBlock('END') 24 | leaderIndices = {0, len(ir)} 25 | leader2IndicesMap = {startBB : 0, endBB : len(ir)} 26 | indices2LeadersMap = {0: startBB, len(ir): endBB} 27 | 28 | # finding leaders in the IR 29 | for idx, item in enumerate(ir): 30 | #print(idx, item) 31 | if isinstance(item[0], ChironAST.ConditionCommand) or isSingle: 32 | # updating then branch meta data 33 | if idx + 1 < len(ir) and (idx + 1 not in leaderIndices): 34 | leaderIndices.add(idx + 1) 35 | thenBranchLeader = BasicBlock(str(idx + 1)) 36 | leader2IndicesMap[thenBranchLeader] = idx + 1 37 | indices2LeadersMap[idx + 1] = thenBranchLeader 38 | 39 | if idx + item[1] < len(ir) and (idx + item[1] 40 | not in leaderIndices) and (isinstance(item[0], ChironAST.ConditionCommand)): 41 | leaderIndices.add(idx + item[1]) 42 | elseBranchLeader = BasicBlock(str(idx + item[1])) 43 | leader2IndicesMap[elseBranchLeader] = idx + item[1] 44 | indices2LeadersMap[idx + item[1]] = elseBranchLeader 45 | 46 | 47 | # adding nodes to Chiron graph 48 | cfg = ChironCFG(cfgName) 49 | for leader in leader2IndicesMap.keys(): 50 | cfg.add_node(leader) 51 | 52 | # partitioning the ir list 53 | # and adding statements to corresponding BasicBlock node 54 | for currLeader in leader2IndicesMap.keys(): 55 | leaderIdx = leader2IndicesMap[currLeader] 56 | currIdx = leaderIdx 57 | while (currIdx < len(ir)): 58 | currLeader.append((ir[currIdx][0], currIdx)) 59 | currIdx += 1 60 | if currIdx in leaderIndices: break 61 | 62 | # adding edges 63 | for node in cfg: 64 | listSize = len(node.instrlist) 65 | if listSize: 66 | irIdx = (node.instrlist[-1])[1] 67 | lastInstr = (node.instrlist[-1])[0] 68 | # print (irIdx, lastInstr, type(lastInstr), isinstance(lastInstr, ChironAST.ConditionCommand)) 69 | if isinstance(lastInstr, ChironAST.ConditionCommand): 70 | if not isinstance(lastInstr.cond, ChironAST.BoolFalse): 71 | thenIdx = irIdx + 1 if (irIdx + 1 < len(ir)) else len(ir) 72 | thenBB = indices2LeadersMap[thenIdx] 73 | cfg.add_edge(node, thenBB, label='Cond_True', color='green') 74 | 75 | if not isinstance(lastInstr.cond, ChironAST.BoolTrue): 76 | elseIdx = irIdx + ir[irIdx][1] if (irIdx + ir[irIdx][1] < len(ir)) else len(ir) 77 | elseBB = indices2LeadersMap[elseIdx] 78 | cfg.add_edge(node, elseBB, label='Cond_False', color='red') 79 | else: 80 | nextBB = indices2LeadersMap[irIdx + 1] if (irIdx + 1 < len(ir)) else endBB 81 | cfg.add_edge(node, nextBB, label='flow_edge', color='blue') 82 | 83 | return cfg 84 | 85 | 86 | 87 | def dumpCFG(cfg, filename="out"): 88 | G = cfg.nxgraph 89 | 90 | # generating custom labels for graph nodes 91 | labels = {} 92 | for node in cfg: 93 | labels[node] = node.label() 94 | # print("bb name : " + node.name + ", ir Id = " + str(node.irID)) 95 | 96 | G = nx.relabel_nodes(G, labels) 97 | A = to_agraph(G) 98 | A.layout('dot') 99 | A.draw(filename + ".png") 100 | -------------------------------------------------------------------------------- /Submission/sbflSubmission.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import sys 5 | import numpy as np 6 | 7 | sys.path.insert(0, "../ChironCore/") 8 | from irhandler import * 9 | from ChironAST.builder import astGenPass 10 | import csv 11 | 12 | 13 | def fitnessScore(IndividualObject): 14 | """ 15 | Parameters 16 | ---------- 17 | IndividualObject : Individual (definition of this class is in ChironCore/sbfl.py) 18 | This is a object of class Individual. The Object has 3 elements 19 | 1. IndividualObject.individual : activity matrix. 20 | type : list, row implies a test 21 | and element of rows are components. 22 | 2. IndividualObject.fitness : fitness of activity matix. 23 | type : float 24 | 3. Indivisual.fitness_valid : a flag used by Genetic Algorithm. 25 | type : boolean 26 | Returns 27 | ------- 28 | fitness_score : flaot 29 | returns the fitness-score of the activity matrix. 30 | Note : No need to set/change fitness and fitness_valid attributes. 31 | """ 32 | # Design the fitness function 33 | fitness_score = 0 34 | activity_mat = np.array(IndividualObject.individual, dtype="int") 35 | activity_mat = activity_mat[:, : activity_mat.shape[1] - 1] 36 | # Use 'activity_mat' to compute fitness of it. 37 | # ToDo : Write your code here to compute fitness of test-suite 38 | 39 | return fitness_score 40 | 41 | 42 | # This class takes a spectrum and generates ranks of each components. 43 | # finish implementation of this class. 44 | class SpectrumBugs: 45 | def __init__(self, spectrum): 46 | self.spectrum = np.array(spectrum, dtype="int") 47 | self.comps = self.spectrum.shape[1] - 1 48 | self.tests = self.spectrum.shape[0] 49 | self.activity_mat = self.spectrum[:, : self.comps] 50 | self.errorVec = self.spectrum[:, -1] 51 | 52 | def getActivity(self, comp_index): 53 | """ 54 | get activity of component 'comp_index' 55 | Parameters 56 | ---------- 57 | comp_index : int 58 | """ 59 | return self.activity_mat[:, comp_index] 60 | 61 | def suspiciousness(self, comp_index): 62 | """ 63 | Parameters 64 | ---------- 65 | comp_index : int 66 | component number/index of which you want to compute how suspicious 67 | the component is. assumption: if a program has 3 components then 68 | they are denoted as c0,c1,c2 i.e 0,1,2 69 | Returns 70 | ------- 71 | sus_score : float 72 | suspiciousness value/score of component 'comp_index' 73 | """ 74 | sus_score = 0 75 | # ToDo : implement the suspiciousness score function. 76 | 77 | return sus_score 78 | 79 | def getRankList(self): 80 | """ 81 | find ranks of each components according to their suspeciousness score. 82 | 83 | Returns 84 | ------- 85 | rankList : list 86 | ranList will contain data in this format: 87 | suppose c1,c2,c3,c4 are components and their ranks are 88 | 1,2,3,4 then rankList will be : 89 | [[c1,1], 90 | [c2,2], 91 | [c3,3], 92 | [c4,4]] 93 | """ 94 | rankList = [] 95 | # ToDo : implement rankList 96 | 97 | return rankList 98 | 99 | 100 | # do not modify this function. 101 | def computeRanks(spectrum, outfilename): 102 | """ 103 | Parameters 104 | ---------- 105 | spectrum : list 106 | spectrum 107 | outfilename : str 108 | components and their ranks. 109 | """ 110 | S = SpectrumBugs(spectrum) 111 | rankList = S.getRankList() 112 | with open(outfilename, "w") as file: 113 | writer = csv.writer(file) 114 | writer.writerows(rankList) 115 | -------------------------------------------------------------------------------- /docs/FuzzingAssigment.md: -------------------------------------------------------------------------------- 1 | # Problem Statement 2 | 3 | It was fun to learn about fuzzing. Clever mutation operators along with nifty coverage metrics makes a naive fuzzer great. In this assignment, you are to implement a 4 | custom mutation operator along with a coverage metric operator (this operator will determines if there is a change/improvement in coverage metric when a turtle 5 | program is executed with mutated inputs.) for the fuzzer loop in `fuzzSubmission.py` file. 6 | 7 | A basic `coverage guided fuzzer` loop has been implemented for you in `fuzzer.py` file. 8 | 9 | Implement the marked functions and class interfaces in `Submission/fuzzSubmission.py` file for this assignment. 10 | 11 | ```python3 12 | - def compareCoverage(curr_metric, total_metric) 13 | - def mutate(input_data) # input_data type is InputObject(...) 14 | - def updateTotalCoverage(curr_metric, total_metric) 15 | ``` 16 | 17 | Points to note. 18 | 19 | - Fuzzing needs initial seed values. Specify using '-d' or '--params' flag. 20 | - Refer to `fuzzer.py` (ChironCore/fuzzer.py) and `fuzzerInterface.py` 21 | (ChironCore/interfaces/fuzzerInterface.py) file for better understanding. (This is optional) 22 | - The last entry in the `Coverage List` is to be ignored if the program terminated successfully on the input run. 23 | [https://github.com/CS639A-PAVT/BugTracker/issues/6](https://github.com/CS639A-PAVT/BugTracker/issues/6) 24 | 25 | Running the `Fuzzer` Loop: (From `ChironCore` folder) 26 | 27 | ```bash 28 | $ ./Chiron.py -t 100 --fuzz example/fuzz2.tl -d '{":x": 5, ":y": 100}' 29 | 30 | 31 | # on termination. sample output 32 | ... 33 | ... 34 | forward :move MoveCommand 1 35 | MoveCommand 36 | ... 37 | [fuzzer] Program took too long to execute. Terminated 38 | [fuzzer] Coverge for execution : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 39 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27] 40 | [fuzzer] Time Exhausted : 10.10099196434021 41 | [fuzzer] Terminating Fuzzer Loop. 42 | Coverage : [], 43 | Corpus: 44 | Input 0 : {':x': 5, ':y': 100} 45 | 46 | ``` 47 | 48 | - Parameters: -t: Time budget for fuzzing in seconds. -d: Specify initial parameters. 49 | 50 | ## Objective 51 | 52 | Mutate the inputs in a way that it `maximizes` coverage within a small time budget. (Eg: Covers as many IR statements in the Turtle program as possible). 53 | We will use a timeout of 60 seconds atleast. Submit 5 interesting testcases on which you were able to maximize the coverage. 54 | 55 | ## Deliverables 56 | 57 | The source code of your implementation. 58 | A brief report (less than 5-pages) describing your implementation, assumptions and limitations. (Understand the difference between the tool's limitation and a bug: any error or missing feature that is caught during evaluation is a bug unless it is listed under the "limitations" section of your tool.) 59 | A set of test cases (at least 5) with the expected output. (tests folder, ChironCore) 60 | 61 | The quality of all the above would affect your marks. The quality of all the above would affect your marks. 62 | Submission Format 63 | 64 | ## Your submission MUST be in the following format 65 | 66 | The submission should be a zip file. 67 | The zip file should be named as assignment*"number"*"Roll-of-student". 68 | Zip the content of the source as is and submit. Don't refactor the base code or move the files around. (ChironCore Folder, Submission Folder, README) 69 | 70 | Please note that your submission will NOT be graded if you do not follow the format. Furthermore, we will use the Readme file provided by you to build and run your code. Therefore, please make sure that the Readme is clear. We cannot grade your submission if we cannot run it on our system. 71 | Some important comments 72 | Before doing anything "extra" (which might fetch bonus marks), first, complete the basic expectations from your implementation. 73 | Program analysis tools are expected to display their results in a user-friendly manner; a user would never like to use a tool that simply spits out a bunch of numbers. So, display the results from your tool suitably. 74 | Discussion is healthy, copying is not. You are encouraged to discuss the assignments, but you must implement the assignments individually. If any two students are found with "similar" pieces of code, both of them will be failed (with no concern as to who was the source). 75 | -------------------------------------------------------------------------------- /ChironCore/interfaces/sExecutionInterface.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | from ChironAST import ChironAST 3 | # sys.path.insert(0, '../Submission/') 4 | # import submission 5 | 6 | 7 | def handleVar(z3Vars, lhs, var): 8 | right = var.__str__() 9 | setAttr(z3Vars,lhs,right.strip().replace(":", "z3Vars.")) 10 | 11 | def handleSum(z3Vars, lhs, expr): 12 | if isinstance(expr.lexpr, ChironAST.Var): 13 | left = expr.lexpr.__str__() 14 | if isinstance(expr.lexpr, ChironAST.Num): 15 | left = expr.lexpr.__str__() 16 | 17 | if isinstance(expr.rexpr, ChironAST.Var): 18 | right = expr.rexpr.__str__() 19 | if isinstance(expr.rexpr, ChironAST.Num): 20 | right = expr.rexpr.__str__() 21 | exp = left.strip().replace(":", "z3Vars.")+"+"+right.strip().replace(":", "z3Vars.") 22 | setAttr(z3Vars,lhs,convertExp(z3Vars,exp)) 23 | 24 | def handleAssignment(z3Vars,stmt): 25 | lhs = str(stmt.lvar).replace(":","") 26 | rhs = str(stmt.rexpr).strip().replace(":", "z3Vars.") 27 | setAttr(z3Vars,lhs,convertExp(z3Vars,rhs)) 28 | 29 | 30 | 31 | class z3Context: 32 | pass 33 | 34 | def convertExp(z3Vars,temp): 35 | _locals = locals() 36 | exec("exp = %s"%(temp),globals(),_locals) 37 | exp = _locals['exp'] 38 | return exp 39 | 40 | def convertTestData(testData): 41 | for tests in testData: 42 | testData[tests]["params"] = convertExp(None,testData[tests]["params"]) 43 | testData[tests]["constparams"] = convertExp(None,testData[tests]["constparams"]) 44 | testData[tests]["coverage"] = convertExp(None,testData[tests]["coverage"]) 45 | testData[tests]["pc"] = convertExp(None,testData[tests]["pc"]) 46 | testData[tests]["pcEval"] = convertExp(None,testData[tests]["pcEval"]) 47 | testData[tests]["symbEnc"] = convertExp(None,testData[tests]["symbEnc"]) 48 | testData[tests]["constraints"] = testData[tests]["constraints"][1:-1].split(",\n") 49 | # print(testData[tests]["constparams"],type(testData[tests]["constparams"])) 50 | return testData 51 | 52 | def setAttr(cls,lhs,rhs): 53 | # print("setAttr",cls,lhs,rhs) 54 | setattr(cls,lhs,rhs) 55 | # exec("setattr(cls,%s,%s)"%("lhs","rhs")) 56 | 57 | 58 | 59 | def getVarName(): 60 | pass 61 | 62 | 63 | class z3Solver(): 64 | def __init__(self, ir): 65 | self.s = Solver() 66 | self.ir = ir 67 | self.z3Vars = z3Context() 68 | self.z3VarMap = {} # mapping between variable string and z3 variable 69 | def resetSolver(self,): 70 | self.s.reset() 71 | 72 | 73 | def initProgramContext(self, params): 74 | del self.z3Vars 75 | self.z3Vars = z3Context() 76 | for key,val in params.items(): 77 | var = key.replace(":","") 78 | setAttr(self.z3Vars,var,Int(var)) 79 | 80 | def handleCondition(self, stmt,negation): 81 | temp = str(stmt).replace(":","self.z3Vars.") 82 | _locals = locals() 83 | try: 84 | exec("exp = %s"%(temp),globals(),_locals) 85 | except: 86 | print("Statement \"",stmt,"\" not supported for symbolic execution") 87 | exit() 88 | exp = _locals['exp'] 89 | if negation: 90 | self.s.add(Not(exp)) 91 | pass 92 | else: 93 | self.s.add(exp) 94 | pass 95 | return str(stmt).replace(":","s.z3Vars.") 96 | 97 | def handleMove(self, stmt): 98 | # TODO 99 | pass 100 | 101 | def handlePen(self, stmt): 102 | # TODO 103 | pass 104 | 105 | def handleGotoCommand(self, stmt): 106 | # TODO 107 | pass 108 | 109 | def handleNoOpCommand(self, stmt): 110 | # TODO 111 | pass 112 | 113 | def eval(self, stmt): 114 | if isinstance(stmt, ChironAST.AssignmentCommand): 115 | handleAssignment(self.z3Vars,stmt) 116 | elif str(stmt)=="False": 117 | pass 118 | elif isinstance(stmt, ChironAST.MoveCommand): 119 | self.handleMove(stmt) 120 | elif isinstance(stmt, ChironAST.PenCommand): 121 | self.handlePen(stmt) 122 | elif isinstance(stmt, ChironAST.GotoCommand): 123 | self.handleGotoCommand(stmt) 124 | elif isinstance(stmt, ChironAST.NoOpCommand): 125 | self.handleNoOpCommand(stmt) 126 | else: 127 | raise NotImplementedError("Unknown instruction: %s, %s."%(type(stmt), stmt)) 128 | pass 129 | -------------------------------------------------------------------------------- /ChironCore/irhandler.py: -------------------------------------------------------------------------------- 1 | import antlr4 2 | import pickle 3 | 4 | from turtparse.parseError import * 5 | from turtparse.tlangParser import tlangParser 6 | from turtparse.tlangLexer import tlangLexer 7 | 8 | from ChironAST import ChironAST 9 | 10 | 11 | def getParseTree(progfl): 12 | input_stream = antlr4.FileStream(progfl) 13 | print(input_stream) 14 | try: 15 | lexer = tlangLexer(input_stream) 16 | stream = antlr4.CommonTokenStream(lexer) 17 | lexer._listeners = [SyntaxErrorListener()] 18 | tparser = tlangParser(stream) 19 | tparser._listeners = [SyntaxErrorListener()] 20 | tree = tparser.start() 21 | except Exception as e: 22 | print("\033[91m\n====================") 23 | print(e.__str__() + "\033[0m\n") 24 | exit(1) 25 | 26 | return tree 27 | 28 | 29 | class IRHandler: 30 | def __init__(self, ir=None, cfg=None): 31 | # statement list 32 | self.ir = ir 33 | # control flow graph 34 | self.cfg = cfg 35 | 36 | def setIR(self, ir): 37 | self.ir = ir 38 | 39 | def setCFG(self, cfg): 40 | self.cfg = cfg 41 | 42 | def dumpIR(self, filename, ir): 43 | with open(filename, "wb") as f: 44 | pickle.dump(ir, f) 45 | 46 | def loadIR(self, filename): 47 | f = open(filename, "rb") 48 | ir = pickle.load(f) 49 | self.ir = ir 50 | return ir 51 | 52 | def updateJump(self, stmtList, index, pos): 53 | stmt, tgt = stmtList[index] 54 | # Don't update the conditional nodes whose 55 | # loops and targets are above the insertion point 56 | # since these don't get affected in any way. 57 | if tgt > 0 and index + tgt > pos: 58 | newTgt = tgt + 1 59 | # update curr conditional instruction's target 60 | stmtList[index] = (stmt, newTgt) 61 | # update the target instruction's jump value 62 | # if it is a backedge, else leave it as is. 63 | backJumpInstr, backJmpTgt = stmtList[index + tgt - 1] 64 | if backJmpTgt < 0: 65 | print(f"Loop Target : {backJumpInstr}, {backJmpTgt}") 66 | stmtList[index + tgt - 1] = (backJumpInstr, backJmpTgt - 1) 67 | 68 | def addInstruction(self, stmtList, inst, pos): 69 | """[summary] 70 | 71 | Args: 72 | stmtList ([List]): List of IR Statments 73 | inst ([ChironAST.Instruction type]): Instruction to be added. Should be of type Instruction(AST). 74 | pos ([int]): Position in IR List to add the instruction. 75 | """ 76 | if pos >= len(stmtList): 77 | print("[error] POSITION given is past the instruction list.") 78 | return 79 | 80 | if isinstance(inst, ChironAST.ConditionCommand): 81 | print("[Skip] Instruction Type not supported for addition. \n") 82 | return 83 | index = 0 84 | 85 | # We must consider the conditional jumps and targets of 86 | # instructions that appear before the position where the 87 | # instruction must be added. Other conditional statements 88 | # will just shift without change of labels since 89 | # all the jump target numbers are relative. 90 | while index < pos: 91 | if isinstance(stmtList[index][0], ChironAST.ConditionCommand): 92 | # Update the target of this conditional statement and the 93 | # target statment's target number accordingly. 94 | updateJump(stmtList, index, pos) 95 | index += 1 96 | # We only allow non-jump statement addition as of now. 97 | stmtList.insert(pos, (inst, 1)) 98 | 99 | def removeInstruction(self, stmtList, pos): 100 | """[summary] 101 | 102 | Replace by a no-op as of now. (Sumit: Kinda works) 103 | 104 | Args: 105 | stmtList ([List]): List of IR Statments 106 | pos ([int]): Position in IR List to remove the instruction. 107 | """ 108 | if pos >= len(stmtList): 109 | print("[error] POSITION given is past the instruction list.") 110 | return 111 | 112 | inst = stmtList[pos][0] 113 | if isinstance(inst, ChironAST.ConditionCommand): 114 | print("[Skip] Instruction Type not supported for removal. \n") 115 | return 116 | 117 | if "__rep_counter_" in str(stmtList[pos][0]): 118 | print("[Skip] Instruction affecting loop counter. \n") 119 | return 120 | 121 | # We only allow non-jump/non-conditional statement removal as of now. 122 | stmtList[pos] = (ChironAST.NoOpCommand(), 1) 123 | 124 | def pretty_print(self, irList): 125 | """ 126 | We pass a IR list and print it here. 127 | """ 128 | print("\n========== Chiron IR ==========\n") 129 | print("The first label before the opcode name represents the IR index or label \non the control flow graph for that node.\n") 130 | print("The number after the opcode name represents the jump offset \nrelative to that statement.\n") 131 | for idx, item in enumerate(irList): 132 | print(f"[L{idx}]".rjust(5), item[0], f"[{item[1]}]") -------------------------------------------------------------------------------- /ChironCore/turtparse/tlangVisitor.py: -------------------------------------------------------------------------------- 1 | # Generated from tlang.g4 by ANTLR 4.7.2 2 | from antlr4 import * 3 | if __name__ is not None and "." in __name__: 4 | from .tlangParser import tlangParser 5 | else: 6 | from tlangParser import tlangParser 7 | 8 | # This class defines a complete generic visitor for a parse tree produced by tlangParser. 9 | 10 | class tlangVisitor(ParseTreeVisitor): 11 | 12 | # Visit a parse tree produced by tlangParser#start. 13 | def visitStart(self, ctx:tlangParser.StartContext): 14 | return self.visitChildren(ctx) 15 | 16 | 17 | # Visit a parse tree produced by tlangParser#instruction_list. 18 | def visitInstruction_list(self, ctx:tlangParser.Instruction_listContext): 19 | return self.visitChildren(ctx) 20 | 21 | 22 | # Visit a parse tree produced by tlangParser#strict_ilist. 23 | def visitStrict_ilist(self, ctx:tlangParser.Strict_ilistContext): 24 | return self.visitChildren(ctx) 25 | 26 | 27 | # Visit a parse tree produced by tlangParser#instruction. 28 | def visitInstruction(self, ctx:tlangParser.InstructionContext): 29 | return self.visitChildren(ctx) 30 | 31 | 32 | # Visit a parse tree produced by tlangParser#conditional. 33 | def visitConditional(self, ctx:tlangParser.ConditionalContext): 34 | return self.visitChildren(ctx) 35 | 36 | 37 | # Visit a parse tree produced by tlangParser#ifConditional. 38 | def visitIfConditional(self, ctx:tlangParser.IfConditionalContext): 39 | return self.visitChildren(ctx) 40 | 41 | 42 | # Visit a parse tree produced by tlangParser#ifElseConditional. 43 | def visitIfElseConditional(self, ctx:tlangParser.IfElseConditionalContext): 44 | return self.visitChildren(ctx) 45 | 46 | 47 | # Visit a parse tree produced by tlangParser#loop. 48 | def visitLoop(self, ctx:tlangParser.LoopContext): 49 | return self.visitChildren(ctx) 50 | 51 | 52 | # Visit a parse tree produced by tlangParser#gotoCommand. 53 | def visitGotoCommand(self, ctx:tlangParser.GotoCommandContext): 54 | return self.visitChildren(ctx) 55 | 56 | 57 | # Visit a parse tree produced by tlangParser#assignment. 58 | def visitAssignment(self, ctx:tlangParser.AssignmentContext): 59 | return self.visitChildren(ctx) 60 | 61 | 62 | # Visit a parse tree produced by tlangParser#moveCommand. 63 | def visitMoveCommand(self, ctx:tlangParser.MoveCommandContext): 64 | return self.visitChildren(ctx) 65 | 66 | 67 | # Visit a parse tree produced by tlangParser#moveOp. 68 | def visitMoveOp(self, ctx:tlangParser.MoveOpContext): 69 | return self.visitChildren(ctx) 70 | 71 | 72 | # Visit a parse tree produced by tlangParser#penCommand. 73 | def visitPenCommand(self, ctx:tlangParser.PenCommandContext): 74 | return self.visitChildren(ctx) 75 | 76 | 77 | # Visit a parse tree produced by tlangParser#pauseCommand. 78 | def visitPauseCommand(self, ctx:tlangParser.PauseCommandContext): 79 | return self.visitChildren(ctx) 80 | 81 | 82 | # Visit a parse tree produced by tlangParser#unaryExpr. 83 | def visitUnaryExpr(self, ctx:tlangParser.UnaryExprContext): 84 | return self.visitChildren(ctx) 85 | 86 | 87 | # Visit a parse tree produced by tlangParser#valueExpr. 88 | def visitValueExpr(self, ctx:tlangParser.ValueExprContext): 89 | return self.visitChildren(ctx) 90 | 91 | 92 | # Visit a parse tree produced by tlangParser#addExpr. 93 | def visitAddExpr(self, ctx:tlangParser.AddExprContext): 94 | return self.visitChildren(ctx) 95 | 96 | 97 | # Visit a parse tree produced by tlangParser#mulExpr. 98 | def visitMulExpr(self, ctx:tlangParser.MulExprContext): 99 | return self.visitChildren(ctx) 100 | 101 | 102 | # Visit a parse tree produced by tlangParser#parenExpr. 103 | def visitParenExpr(self, ctx:tlangParser.ParenExprContext): 104 | return self.visitChildren(ctx) 105 | 106 | 107 | # Visit a parse tree produced by tlangParser#multiplicative. 108 | def visitMultiplicative(self, ctx:tlangParser.MultiplicativeContext): 109 | return self.visitChildren(ctx) 110 | 111 | 112 | # Visit a parse tree produced by tlangParser#additive. 113 | def visitAdditive(self, ctx:tlangParser.AdditiveContext): 114 | return self.visitChildren(ctx) 115 | 116 | 117 | # Visit a parse tree produced by tlangParser#unaryArithOp. 118 | def visitUnaryArithOp(self, ctx:tlangParser.UnaryArithOpContext): 119 | return self.visitChildren(ctx) 120 | 121 | 122 | # Visit a parse tree produced by tlangParser#condition. 123 | def visitCondition(self, ctx:tlangParser.ConditionContext): 124 | return self.visitChildren(ctx) 125 | 126 | 127 | # Visit a parse tree produced by tlangParser#binCondOp. 128 | def visitBinCondOp(self, ctx:tlangParser.BinCondOpContext): 129 | return self.visitChildren(ctx) 130 | 131 | 132 | # Visit a parse tree produced by tlangParser#logicOp. 133 | def visitLogicOp(self, ctx:tlangParser.LogicOpContext): 134 | return self.visitChildren(ctx) 135 | 136 | 137 | # Visit a parse tree produced by tlangParser#value. 138 | def visitValue(self, ctx:tlangParser.ValueContext): 139 | return self.visitChildren(ctx) 140 | 141 | 142 | 143 | del tlangParser -------------------------------------------------------------------------------- /ChironCore/abstractInterpretation.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This file implements the worklist algorithm. 3 | WorkList class is the class for worklist queue 4 | and necessary functions to operate on the worklist. 5 | worklistAlgorithm actually implements the worklist algorithm. 6 | ''' 7 | 8 | from queue import Queue 9 | import sys 10 | import cfg.cfgBuilder as cfgB 11 | import cfg.ChironCFG as cfgK 12 | 13 | sys.path.insert(0, '../Submission/') 14 | from submissionAI import * 15 | from interpreter import * 16 | from lattice import * 17 | 18 | class WorkList(): 19 | ''' 20 | initialize the worklist with the basic blocks list 21 | ''' 22 | def __init__(self, BBList): 23 | self.worklist = Queue(maxsize = 0) 24 | for i in BBList: 25 | if i.name == "END": continue 26 | self.worklist.put(i) 27 | 28 | def enQueue(self, obj): 29 | if not isinstance(obj, cfgK.BasicBlock): 30 | raise ValueError("Enqueue Basic Block only") 31 | if self.worklist.full(): 32 | print("Worklist is full") 33 | raise ValueError("Worklist is full") 34 | self.worklist.put(obj) 35 | 36 | def deQueue(self): 37 | if self.worklist.empty(): 38 | print("Worklist is empty") 39 | return None 40 | obj = self.worklist.get() 41 | return obj 42 | 43 | def isEmpty(self): 44 | return self.worklist.empty() 45 | 46 | def getSize(self): 47 | return self.worklist.qsize() 48 | 49 | 50 | class AbstractInterpreter(Interpreter): 51 | def __init__(self, irHandler): 52 | super().__init__(irHandler) 53 | self.pc = 0 54 | self.controlFlowGraph = irHandler.cfg 55 | self.workList = WorkList(self.controlFlowGraph.nodes()) 56 | self.analysis = ForwardAnalysis() 57 | 58 | #just a dummy equallity check function 59 | def isDifferent(self, dA, dB): 60 | for i in dA.keys(): 61 | if i not in dB.keys(): 62 | return True 63 | if dA[i] != dB[i]: 64 | return True 65 | return False 66 | 67 | 68 | def isChanged(self, newOut, oldOut): 69 | ''' 70 | return True if newOut is different than their older values(oldOut) 71 | before calling to the TransferFunction 72 | ''' 73 | assert isinstance(newOut, list) 74 | assert isinstance(oldOut, list) 75 | if len(newOut) != len(oldOut): 76 | return True 77 | flag = False 78 | for i in range(len(newOut)): 79 | flag = (flag or self.isDifferent(newOut[i], oldOut[i])) 80 | 81 | return flag 82 | 83 | 84 | def worklistAlgorithm(self, cfg): 85 | ''' 86 | This is the main worklist algorithm. 87 | Initializing the worklist with the basic block list 88 | It is an map from name of the BB to the in and out info of program states 89 | ''' 90 | BBlist = cfg.nodes() 91 | bbIn = {} 92 | bbOut = {} 93 | 94 | ''' 95 | initialise in/out of entry/exit point 96 | ''' 97 | for i in BBlist: 98 | bbIn[i.name] = self.analysis.initialize(i, i.name == "START") 99 | bbOut[i.name] = [] 100 | 101 | while not self.workList.isEmpty(): 102 | currBB = self.workList.deQueue() 103 | oldOut = bbOut[currBB.name] 104 | 105 | predList = [p for p in cfg.predecessors(currBB)] 106 | 107 | # cumulate the out of the pred list 108 | inlist = [] 109 | for pred in predList: 110 | label = cfg.get_edge_label(pred, currBB) 111 | if bbOut[pred.name]: 112 | if label != 'Cond_False': 113 | # See CFGBuilder function we have 114 | # cfg.add_edge(node, thenBB, label='Cond_True', color='green') 115 | # and 116 | # cfg.add_edge(node, thenBB, label='Cond_False', color='red') 117 | inlist.append(bbOut[pred.name][0]) 118 | else: 119 | assert len(bbOut[pred.name]) > 1 120 | inlist.append(bbOut[pred.name][1]) 121 | 122 | # calling meet operation over inlist 123 | if inlist: 124 | currInVal = self.analysis.meet(inlist) 125 | assert isinstance(currInVal, dict) 126 | #assign the returned value to the in of currBB 127 | bbIn[currBB.name] = currInVal 128 | 129 | #calling transfer function 130 | tf = self.analysis.transferFunctionInstance 131 | currBBOutVal = tf.transferFunction(bbIn[currBB.name], currBB) 132 | ''' 133 | 1) return value should be a list 134 | 2) len(currBBOutVal) at most be 2 135 | 3) if len(currBBOutVal) == 2, then 136 | currBBOutVal[0] -> for true branch 137 | currBBOutVal[1] -> for false branch 138 | ''' 139 | assert isinstance(currBBOutVal, list) 140 | bbOut[currBB.name] = currBBOutVal 141 | 142 | if self.isChanged(bbOut[currBB.name], oldOut): 143 | nextBBList = cfg.successors(currBB) 144 | for i in nextBBList: 145 | self.workList.enQueue(i) 146 | 147 | #print("Worklist empty") 148 | return bbIn, bbOut 149 | -------------------------------------------------------------------------------- /ChironCore/ChironAST/ChironAST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # Abstract syntax tree for ChironLang 4 | 5 | class AST(object): 6 | pass 7 | 8 | 9 | # --Instruction Classes----------------------------------------------- 10 | 11 | class Instruction(AST): 12 | pass 13 | 14 | 15 | class AssignmentCommand(Instruction): 16 | def __init__(self, leftvar, rexpr): 17 | self.lvar = leftvar 18 | self.rexpr = rexpr 19 | 20 | def __str__(self): 21 | return self.lvar.__str__() + " = " + self.rexpr.__str__() 22 | 23 | 24 | class ConditionCommand(Instruction): 25 | def __init__(self, condition): 26 | self.cond = condition 27 | 28 | def __str__(self): 29 | return self.cond.__str__() 30 | 31 | # Not Implemented Yet. 32 | class AssertCommand(Instruction): 33 | def __init__(self, condition): 34 | self.cond = condition 35 | 36 | def __str__(self): 37 | return self.cond.__str__() 38 | 39 | class MoveCommand(Instruction): 40 | def __init__(self, motion, expr): 41 | self.direction = motion 42 | self.expr = expr 43 | 44 | def __str__(self): 45 | return self.direction + " " + self.expr.__str__() 46 | 47 | 48 | class PenCommand(Instruction): 49 | def __init__(self, penstat): 50 | self.status = penstat 51 | 52 | def __str__(self): 53 | return self.status 54 | 55 | class GotoCommand(Instruction): 56 | def __init__(self, x, y): 57 | self.xcor = x 58 | self.ycor = y 59 | 60 | def __str__(self): 61 | return "goto " + str(self.xcor) + " " + str(self.ycor) 62 | 63 | class NoOpCommand(Instruction): 64 | def __init__(self): 65 | pass 66 | 67 | def __str__(self): 68 | return "NOP" 69 | 70 | class PauseCommand(Instruction): 71 | def __init__(self): 72 | pass 73 | 74 | def __str__(self): 75 | return "pause" 76 | 77 | class Expression(AST): 78 | pass 79 | 80 | 81 | # --Arithmetic Expressions-------------------------------------------- 82 | 83 | class ArithExpr(Expression): 84 | pass 85 | 86 | 87 | class BinArithOp(ArithExpr): 88 | def __init__(self, expr1, expr2, opsymbol): 89 | self.lexpr = expr1 90 | self.rexpr = expr2 91 | self.symbol = opsymbol 92 | 93 | def __str__(self): 94 | return "(" + self.lexpr.__str__() + " " + self.symbol + " " + self.rexpr.__str__() + ")" 95 | 96 | 97 | class UnaryArithOp(ArithExpr): 98 | def __init__(self, expr1, opsymbol): 99 | self.expr = expr1 100 | self.symbol = opsymbol 101 | 102 | def __str__(self): 103 | return self.symbol + self.expr.__str__() 104 | 105 | 106 | class UMinus(UnaryArithOp): 107 | def __init__(self, lexpr): 108 | super().__init__(lexpr, "-") 109 | 110 | 111 | class Sum(BinArithOp): 112 | def __init__(self, lexpr, rexpr): 113 | super().__init__(lexpr, rexpr, "+") 114 | 115 | 116 | class Diff(BinArithOp): 117 | def __init__(self, lexpr, rexpr): 118 | super().__init__(lexpr, rexpr, "-") 119 | 120 | 121 | class Mult(BinArithOp): 122 | def __init__(self, lexpr, rexpr): 123 | super().__init__(lexpr, rexpr, "*") 124 | 125 | class Div(BinArithOp): 126 | def __init__(self, lexpr, rexpr): 127 | super().__init__(lexpr, rexpr, "/") 128 | 129 | 130 | # --Boolean Expressions----------------------------------------------- 131 | 132 | class BoolExpr(Expression): 133 | pass 134 | 135 | 136 | class BinCondOp(BoolExpr): 137 | def __init__(self, expr1, expr2, opsymbol): 138 | self.lexpr = expr1 139 | self.rexpr = expr2 140 | self.symbol = opsymbol 141 | 142 | def __str__(self): 143 | return "(" + self.lexpr.__str__() + ' ' + self.symbol + ' ' + self.rexpr.__str__() + ")" 144 | 145 | 146 | class AND(BinCondOp): 147 | def __init__(self, expr1, expr2): 148 | super().__init__(expr1, expr2, "and") 149 | 150 | class OR(BinCondOp): 151 | def __init__(self, expr1, expr2): 152 | super().__init__(expr1, expr2, "or") 153 | 154 | 155 | class LT(BinCondOp): 156 | def __init__(self, expr1, expr2): 157 | super().__init__(expr1, expr2, "<") 158 | 159 | 160 | class GT(BinCondOp): 161 | def __init__(self, expr1, expr2): 162 | super().__init__(expr1, expr2, ">") 163 | 164 | 165 | class LTE(BinCondOp): 166 | def __init__(self, expr1, expr2): 167 | super().__init__(expr1, expr2, "<=") 168 | 169 | 170 | class GTE(BinCondOp): 171 | def __init__(self, expr1, expr2): 172 | super().__init__(expr1, expr2, ">=") 173 | 174 | 175 | class EQ(BinCondOp): 176 | def __init__(self, expr1, expr2): 177 | super().__init__(expr1, expr2, "==") 178 | 179 | 180 | class NEQ(BinCondOp): 181 | def __init__(self, expr1, expr2): 182 | super().__init__(expr1, expr2, "!=") 183 | 184 | 185 | class NOT(BoolExpr): 186 | def __init__(self, uexpr): 187 | self.expr = uexpr 188 | self.symbol = "not" 189 | 190 | def __str__(self): 191 | return self.symbol + self.expr.__str__() 192 | 193 | 194 | class PenStatus(BoolExpr): 195 | def __init__(self): 196 | pass 197 | 198 | def __str__(self): 199 | return "pendown?" 200 | 201 | 202 | class BoolTrue(BoolExpr): 203 | def __init__(self): 204 | pass 205 | 206 | def __str__(self): 207 | return "True" 208 | 209 | 210 | class BoolFalse(BoolExpr): 211 | def __init__(self): 212 | pass 213 | 214 | def __str__(self): 215 | return "False" 216 | 217 | 218 | class Value(Expression): 219 | pass 220 | 221 | 222 | class Num(Value): 223 | def __init__(self, v): 224 | self.val = int(v) 225 | 226 | def __str__(self): 227 | return str(self.val) 228 | 229 | 230 | class Var(Value): 231 | def __init__(self, vname): 232 | self.varname = vname 233 | 234 | def __str__(self): 235 | return self.varname 236 | -------------------------------------------------------------------------------- /ChironCore/turtparse/tlang.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | 'if' 4 | '[' 5 | ']' 6 | 'else' 7 | 'repeat' 8 | 'goto' 9 | '(' 10 | ',' 11 | ')' 12 | '=' 13 | 'forward' 14 | 'backward' 15 | 'left' 16 | 'right' 17 | 'penup' 18 | 'pendown' 19 | 'pause' 20 | '+' 21 | '-' 22 | '*' 23 | '/' 24 | 'pendown?' 25 | '<' 26 | '>' 27 | '==' 28 | '!=' 29 | '<=' 30 | '>=' 31 | '&&' 32 | '||' 33 | '!' 34 | null 35 | null 36 | null 37 | null 38 | 39 | token symbolic names: 40 | null 41 | null 42 | null 43 | null 44 | null 45 | null 46 | null 47 | null 48 | null 49 | null 50 | null 51 | null 52 | null 53 | null 54 | null 55 | null 56 | null 57 | null 58 | PLUS 59 | MINUS 60 | MUL 61 | DIV 62 | PENCOND 63 | LT 64 | GT 65 | EQ 66 | NEQ 67 | LTE 68 | GTE 69 | AND 70 | OR 71 | NOT 72 | NUM 73 | VAR 74 | NAME 75 | Whitespace 76 | 77 | rule names: 78 | start 79 | instruction_list 80 | strict_ilist 81 | instruction 82 | conditional 83 | ifConditional 84 | ifElseConditional 85 | loop 86 | gotoCommand 87 | assignment 88 | moveCommand 89 | moveOp 90 | penCommand 91 | pauseCommand 92 | expression 93 | multiplicative 94 | additive 95 | unaryArithOp 96 | condition 97 | binCondOp 98 | logicOp 99 | value 100 | 101 | 102 | atn: 103 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 37, 175, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 3, 2, 3, 2, 3, 2, 3, 3, 7, 3, 51, 10, 3, 12, 3, 14, 3, 54, 11, 3, 3, 4, 6, 4, 57, 10, 4, 13, 4, 14, 4, 58, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 68, 10, 5, 3, 6, 3, 6, 5, 6, 72, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 5, 16, 125, 10, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 7, 16, 135, 10, 16, 12, 16, 14, 16, 138, 11, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 158, 10, 20, 3, 20, 3, 20, 3, 20, 3, 20, 7, 20, 164, 10, 20, 12, 20, 14, 20, 167, 11, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 2, 4, 30, 38, 24, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 2, 9, 3, 2, 13, 16, 3, 2, 17, 18, 3, 2, 22, 23, 3, 2, 20, 21, 3, 2, 25, 30, 3, 2, 31, 32, 3, 2, 34, 35, 2, 169, 2, 46, 3, 2, 2, 2, 4, 52, 3, 2, 2, 2, 6, 56, 3, 2, 2, 2, 8, 67, 3, 2, 2, 2, 10, 71, 3, 2, 2, 2, 12, 73, 3, 2, 2, 2, 14, 79, 3, 2, 2, 2, 16, 89, 3, 2, 2, 2, 18, 95, 3, 2, 2, 2, 20, 102, 3, 2, 2, 2, 22, 106, 3, 2, 2, 2, 24, 109, 3, 2, 2, 2, 26, 111, 3, 2, 2, 2, 28, 113, 3, 2, 2, 2, 30, 124, 3, 2, 2, 2, 32, 139, 3, 2, 2, 2, 34, 141, 3, 2, 2, 2, 36, 143, 3, 2, 2, 2, 38, 157, 3, 2, 2, 2, 40, 168, 3, 2, 2, 2, 42, 170, 3, 2, 2, 2, 44, 172, 3, 2, 2, 2, 46, 47, 5, 4, 3, 2, 47, 48, 7, 2, 2, 3, 48, 3, 3, 2, 2, 2, 49, 51, 5, 8, 5, 2, 50, 49, 3, 2, 2, 2, 51, 54, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 53, 3, 2, 2, 2, 53, 5, 3, 2, 2, 2, 54, 52, 3, 2, 2, 2, 55, 57, 5, 8, 5, 2, 56, 55, 3, 2, 2, 2, 57, 58, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 58, 59, 3, 2, 2, 2, 59, 7, 3, 2, 2, 2, 60, 68, 5, 20, 11, 2, 61, 68, 5, 10, 6, 2, 62, 68, 5, 16, 9, 2, 63, 68, 5, 22, 12, 2, 64, 68, 5, 26, 14, 2, 65, 68, 5, 18, 10, 2, 66, 68, 5, 28, 15, 2, 67, 60, 3, 2, 2, 2, 67, 61, 3, 2, 2, 2, 67, 62, 3, 2, 2, 2, 67, 63, 3, 2, 2, 2, 67, 64, 3, 2, 2, 2, 67, 65, 3, 2, 2, 2, 67, 66, 3, 2, 2, 2, 68, 9, 3, 2, 2, 2, 69, 72, 5, 12, 7, 2, 70, 72, 5, 14, 8, 2, 71, 69, 3, 2, 2, 2, 71, 70, 3, 2, 2, 2, 72, 11, 3, 2, 2, 2, 73, 74, 7, 3, 2, 2, 74, 75, 5, 38, 20, 2, 75, 76, 7, 4, 2, 2, 76, 77, 5, 6, 4, 2, 77, 78, 7, 5, 2, 2, 78, 13, 3, 2, 2, 2, 79, 80, 7, 3, 2, 2, 80, 81, 5, 38, 20, 2, 81, 82, 7, 4, 2, 2, 82, 83, 5, 6, 4, 2, 83, 84, 7, 5, 2, 2, 84, 85, 7, 6, 2, 2, 85, 86, 7, 4, 2, 2, 86, 87, 5, 6, 4, 2, 87, 88, 7, 5, 2, 2, 88, 15, 3, 2, 2, 2, 89, 90, 7, 7, 2, 2, 90, 91, 5, 44, 23, 2, 91, 92, 7, 4, 2, 2, 92, 93, 5, 6, 4, 2, 93, 94, 7, 5, 2, 2, 94, 17, 3, 2, 2, 2, 95, 96, 7, 8, 2, 2, 96, 97, 7, 9, 2, 2, 97, 98, 5, 30, 16, 2, 98, 99, 7, 10, 2, 2, 99, 100, 5, 30, 16, 2, 100, 101, 7, 11, 2, 2, 101, 19, 3, 2, 2, 2, 102, 103, 7, 35, 2, 2, 103, 104, 7, 12, 2, 2, 104, 105, 5, 30, 16, 2, 105, 21, 3, 2, 2, 2, 106, 107, 5, 24, 13, 2, 107, 108, 5, 30, 16, 2, 108, 23, 3, 2, 2, 2, 109, 110, 9, 2, 2, 2, 110, 25, 3, 2, 2, 2, 111, 112, 9, 3, 2, 2, 112, 27, 3, 2, 2, 2, 113, 114, 7, 19, 2, 2, 114, 29, 3, 2, 2, 2, 115, 116, 8, 16, 1, 2, 116, 117, 5, 36, 19, 2, 117, 118, 5, 30, 16, 7, 118, 125, 3, 2, 2, 2, 119, 125, 5, 44, 23, 2, 120, 121, 7, 9, 2, 2, 121, 122, 5, 30, 16, 2, 122, 123, 7, 11, 2, 2, 123, 125, 3, 2, 2, 2, 124, 115, 3, 2, 2, 2, 124, 119, 3, 2, 2, 2, 124, 120, 3, 2, 2, 2, 125, 136, 3, 2, 2, 2, 126, 127, 12, 6, 2, 2, 127, 128, 5, 32, 17, 2, 128, 129, 5, 30, 16, 7, 129, 135, 3, 2, 2, 2, 130, 131, 12, 5, 2, 2, 131, 132, 5, 34, 18, 2, 132, 133, 5, 30, 16, 6, 133, 135, 3, 2, 2, 2, 134, 126, 3, 2, 2, 2, 134, 130, 3, 2, 2, 2, 135, 138, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 136, 137, 3, 2, 2, 2, 137, 31, 3, 2, 2, 2, 138, 136, 3, 2, 2, 2, 139, 140, 9, 4, 2, 2, 140, 33, 3, 2, 2, 2, 141, 142, 9, 5, 2, 2, 142, 35, 3, 2, 2, 2, 143, 144, 7, 21, 2, 2, 144, 37, 3, 2, 2, 2, 145, 146, 8, 20, 1, 2, 146, 147, 7, 33, 2, 2, 147, 158, 5, 38, 20, 7, 148, 149, 5, 30, 16, 2, 149, 150, 5, 40, 21, 2, 150, 151, 5, 30, 16, 2, 151, 158, 3, 2, 2, 2, 152, 158, 7, 24, 2, 2, 153, 154, 7, 9, 2, 2, 154, 155, 5, 38, 20, 2, 155, 156, 7, 11, 2, 2, 156, 158, 3, 2, 2, 2, 157, 145, 3, 2, 2, 2, 157, 148, 3, 2, 2, 2, 157, 152, 3, 2, 2, 2, 157, 153, 3, 2, 2, 2, 158, 165, 3, 2, 2, 2, 159, 160, 12, 5, 2, 2, 160, 161, 5, 42, 22, 2, 161, 162, 5, 38, 20, 6, 162, 164, 3, 2, 2, 2, 163, 159, 3, 2, 2, 2, 164, 167, 3, 2, 2, 2, 165, 163, 3, 2, 2, 2, 165, 166, 3, 2, 2, 2, 166, 39, 3, 2, 2, 2, 167, 165, 3, 2, 2, 2, 168, 169, 9, 6, 2, 2, 169, 41, 3, 2, 2, 2, 170, 171, 9, 7, 2, 2, 171, 43, 3, 2, 2, 2, 172, 173, 9, 8, 2, 2, 173, 45, 3, 2, 2, 2, 11, 52, 58, 67, 71, 124, 134, 136, 157, 165] -------------------------------------------------------------------------------- /ChironCore/interpreter.py: -------------------------------------------------------------------------------- 1 | 2 | from ChironAST import ChironAST 3 | from ChironHooks import Chironhooks 4 | import turtle 5 | 6 | Release="Chiron v5.3" 7 | 8 | def addContext(s): 9 | return str(s).strip().replace(":", "self.prg.") 10 | 11 | class Interpreter: 12 | # Turtle program should not contain variable with names "ir", "pc", "t_screen" 13 | ir = None 14 | pc = None 15 | t_screen = None 16 | trtl = None 17 | 18 | def __init__(self, irHandler, params): 19 | self.ir = irHandler.ir 20 | self.cfg = irHandler.cfg 21 | self.pc = 0 22 | self.t_screen = turtle.getscreen() 23 | self.trtl = turtle.Turtle() 24 | self.trtl.shape("turtle") 25 | self.trtl.color("blue", "yellow") 26 | self.trtl.fillcolor("green") 27 | self.trtl.begin_fill() 28 | self.trtl.pensize(4) 29 | self.trtl.speed(1) # TODO: Make it user friendly 30 | 31 | if params is not None: 32 | self.args = params 33 | else: 34 | self.args = None 35 | 36 | turtle.title(Release) 37 | turtle.bgcolor("white") 38 | turtle.hideturtle() 39 | 40 | def handleAssignment(self, stmt,tgt): 41 | raise NotImplementedError('Assignments are not handled!') 42 | 43 | def handleCondition(self, stmt, tgt): 44 | raise NotImplementedError('Conditions are not handled!') 45 | 46 | def handleMove(self, stmt, tgt): 47 | raise NotImplementedError('Moves are not handled!') 48 | 49 | def handlePen(self, stmt, tgt): 50 | raise NotImplementedError('Pens are not handled!') 51 | 52 | def handleGotoCommand(self, stmt, tgt): 53 | raise NotImplementedError('Gotos are not handled!') 54 | 55 | def handleNoOpCommand(self, stmt, tgt): 56 | raise NotImplementedError('No-Ops are not handled!') 57 | 58 | def handlePauseCommand(self, stmt, tgt): 59 | raise NotImplementedError('No-Ops are not handled!') 60 | 61 | def sanityCheck(self, irInstr): 62 | stmt, tgt = irInstr 63 | # if not a condition command, rel. jump can't be anything but 1 64 | if not isinstance(stmt, ChironAST.ConditionCommand): 65 | if tgt != 1: 66 | raise ValueError("Improper relative jump for non-conditional instruction", str(stmt), tgt) 67 | 68 | def interpret(self): 69 | pass 70 | 71 | def initProgramContext(self, params): 72 | pass 73 | 74 | class ProgramContext: 75 | pass 76 | 77 | # TODO: move to a different file 78 | class ConcreteInterpreter(Interpreter): 79 | # Ref: https://realpython.com/beginners-guide-python-turtle 80 | cond_eval = None # used as a temporary variable within the embedded program interpreter 81 | prg = None 82 | 83 | def __init__(self, irHandler, params): 84 | super().__init__(irHandler, params) 85 | self.prg = ProgramContext() 86 | # Hooks Object: 87 | if self.args is not None and self.args.hooks: 88 | self.chironhook = Chironhooks.ConcreteChironHooks() 89 | self.pc = 0 90 | 91 | def interpret(self): 92 | print("Program counter : ", self.pc) 93 | stmt, tgt = self.ir[self.pc] 94 | print(stmt, stmt.__class__.__name__, tgt) 95 | 96 | self.sanityCheck(self.ir[self.pc]) 97 | 98 | if isinstance(stmt, ChironAST.AssignmentCommand): 99 | ntgt = self.handleAssignment(stmt, tgt) 100 | elif isinstance(stmt, ChironAST.ConditionCommand): 101 | ntgt = self.handleCondition(stmt, tgt) 102 | elif isinstance(stmt, ChironAST.MoveCommand): 103 | ntgt = self.handleMove(stmt, tgt) 104 | elif isinstance(stmt, ChironAST.PenCommand): 105 | ntgt = self.handlePen(stmt, tgt) 106 | elif isinstance(stmt, ChironAST.GotoCommand): 107 | ntgt = self.handleGotoCommand(stmt, tgt) 108 | elif isinstance(stmt, ChironAST.NoOpCommand): 109 | ntgt = self.handleNoOpCommand(stmt, tgt) 110 | else: 111 | raise NotImplementedError("Unknown instruction: %s, %s."%(type(stmt), stmt)) 112 | 113 | # TODO: handle statement 114 | self.pc += ntgt 115 | 116 | if self.pc >= len(self.ir): 117 | # This is the ending of the interpreter. 118 | self.trtl.write("End, Press ESC", font=("Arial", 15, "bold")) 119 | if self.args is not None and self.args.hooks: 120 | self.chironhook.ChironEndHook(self) 121 | return True 122 | else: 123 | return False 124 | 125 | def initProgramContext(self, params): 126 | # This is the starting of the interpreter at setup stage. 127 | if self.args is not None and self.args.hooks: 128 | self.chironhook.ChironStartHook(self) 129 | self.trtl.write("Start", font=("Arial", 15, "bold")) 130 | for key,val in params.items(): 131 | var = key.replace(":","") 132 | exec("setattr(self.prg,\"%s\",%s)" % (var, val)) 133 | 134 | def handleAssignment(self, stmt, tgt): 135 | print(" Assignment Statement") 136 | lhs = str(stmt.lvar).replace(":","") 137 | rhs = addContext(stmt.rexpr) 138 | exec("setattr(self.prg,\"%s\",%s)" % (lhs,rhs)) 139 | return 1 140 | 141 | def handleCondition(self, stmt, tgt): 142 | print(" Branch Instruction") 143 | condstr = addContext(stmt) 144 | exec("self.cond_eval = %s" % (condstr)) 145 | return 1 if self.cond_eval else tgt 146 | 147 | def handleMove(self, stmt, tgt): 148 | print(" MoveCommand") 149 | exec("self.trtl.%s(%s)" % (stmt.direction,addContext(stmt.expr))) 150 | return 1 151 | 152 | def handleNoOpCommand(self, stmt, tgt): 153 | print(" No-Op Command") 154 | return 1 155 | 156 | def handlePen(self, stmt, tgt): 157 | print(" PenCommand") 158 | exec("self.trtl.%s()"%(stmt.status)) 159 | return 1 160 | 161 | def handleGotoCommand(self, stmt, tgt): 162 | print(" GotoCommand") 163 | xcor = addContext(stmt.xcor) 164 | ycor = addContext(stmt.ycor) 165 | exec("self.trtl.goto(%s, %s)" % (xcor, ycor)) 166 | return 1 167 | -------------------------------------------------------------------------------- /ChironCore/fuzzer.py: -------------------------------------------------------------------------------- 1 | ## Coverage Guided Fuzzing 2 | 3 | """ 4 | This file implements the main fuzzer loop. 5 | Pick an input using a distribution, mutate it 6 | run the program with the mutated input and return 7 | coverage metric and compare to previous metric to 8 | check if we found any improvement due to the mutation. 9 | 10 | This loop continues until time limit is exhausted or we 11 | ran out of inputs inorder to continue mutations for the 12 | fuzzer loop. 13 | """ 14 | 15 | import sys 16 | import time 17 | import random 18 | import copy 19 | import uuid 20 | from interpreter import * 21 | 22 | sys.path.insert(0, "../Submission/") 23 | from fuzzSubmission import * 24 | 25 | 26 | class InputObject: 27 | def __init__(self, data): 28 | self.id = str(uuid.uuid4()) 29 | self.data = data 30 | # Flag to check if ever picked 31 | # for mutation or not. 32 | self.pickedOnce = False 33 | 34 | 35 | class Fuzzer(ConcreteInterpreter): 36 | # Execute the program using the input from mutator 37 | def __init__(self, irHandler, args): 38 | """ 39 | ir (List): List of program IR statments 40 | params (dict): Mapped variables with initial assignments. 41 | """ 42 | super().__init__(irHandler, args) 43 | self.ir = irHandler.ir 44 | self.params = args.params 45 | self.args = args 46 | self.corpus = [] 47 | self.timeout = 0 48 | self.customMutator = CustomMutator() # From submission 49 | self.coverage = CustomCoverageMetric() # From submission 50 | 51 | def handleExecution(self, ir, inputList={}, end=0): 52 | coverage = [] 53 | terminated = False 54 | self.pc = 0 55 | self.initProgramContext(inputList) 56 | coverage.append(self.pc) 57 | # The maximum time for one execution of the 58 | # fuzzed program must be less than end time. 59 | while time.monotonic() <= end: 60 | terminated = self.interpret() 61 | # List of PC values -> Execution Trace -> Stmts Hit! 62 | coverage.append(self.pc) 63 | if terminated: 64 | break 65 | if time.monotonic() >= end: 66 | print("[fuzzer] Program took too long to execute. Terminated") 67 | else: 68 | print("[fuzzer] Program Ended.") 69 | return list(set(coverage)) 70 | 71 | def seedCorpusRandom(self, varsList): 72 | # HonggFuzz starts with a buffer of atleast 73 | # four elements. Lets start with 8 say. 74 | for _ in range(8): 75 | inputDict = {} 76 | for variable in varsList: 77 | inputDict[variable] = random.randint(-10, 10) 78 | input_i = InputObject(data=inputDict) 79 | self.corpus.append(input_i) 80 | 81 | def fuzz(self, timeLimit=0, generateRandom=False): 82 | """[summary] 83 | 84 | Args: 85 | timeLimit (float/int): Total time(sec) to run the fuzzer loop for. 86 | generateRandom (boolean): Whether to generate random seed inputs at the starting. 87 | 88 | Returns: 89 | tuple (coverage, corpus) : Return coverage information and corpus of inputs used for fuzzing. 90 | """ 91 | 92 | # If Dummy List needed. 93 | if generateRandom: 94 | varList = [] 95 | for key, _ in self.params.items(): 96 | variable = key.replace(":", "").strip() 97 | varList.append(variable) 98 | self.seedCorpusRandom(varList) 99 | 100 | # get the variables used in the program. 101 | 102 | print(f"[fuzzer] Starting Fuzzer : init args -> {self.params}") 103 | 104 | # Initial Seed values from user. 105 | temp_input = InputObject(data=self.params) 106 | self.corpus.append(temp_input) 107 | 108 | start_time = time.monotonic() 109 | # Fuzzing ends at this timestamp. 110 | endTime = time.monotonic() + timeLimit 111 | 112 | # Either supply dummy corpus 113 | # or use user-provided inputs. 114 | while True: 115 | # Initialize current coverage to empty as loop starts. 116 | self.coverage.curr_metric = [] 117 | 118 | # Pick a random input and choose it for mutation. 119 | pickedInput = random.choice(self.corpus) 120 | 121 | # Set this flag since the input is picked once now. 122 | pickedInput.pickedOnce = True 123 | print(f"[fuzzer] Fuzzing with Input ID : {pickedInput.id}") 124 | pickInputRandom = copy.deepcopy(pickedInput) 125 | 126 | pickInputRandom.pickedOnce = False 127 | mutated_input = self.customMutator.mutate( 128 | pickInputRandom, self.coverage, self.ir 129 | ) 130 | 131 | # Get new coverage from execution. 132 | # The maximum time for one execution of the 133 | # fuzzed program must be less than end time. 134 | self.coverage.curr_metric = self.handleExecution( 135 | self.ir, mutated_input.data, end=endTime 136 | ) 137 | # Print the coverage : Representational 138 | print(f"[fuzzer] Coverge for execution : {self.coverage.curr_metric}") 139 | 140 | # Check if coverage improved. 141 | if self.coverage.compareCoverage( 142 | self.coverage.curr_metric, self.coverage.total_metric 143 | ): 144 | mutated_input.id = str(uuid.uuid4()) 145 | mutated_input.pickedOnce = False 146 | self.coverage.total_metric = self.coverage.updateTotalCoverage( 147 | self.coverage.curr_metric, self.coverage.total_metric 148 | ) 149 | # Add mutated input if coverage improved. 150 | self.corpus.append(mutated_input) 151 | 152 | exhaustedBudget = True if time.monotonic() >= endTime else False 153 | if exhaustedBudget: 154 | time_delta = time.monotonic() - start_time 155 | print(f"[fuzzer] Time Exhausted : {time_delta}") 156 | break 157 | 158 | print(f"[fuzzer] Terminating Fuzzer Loop.") 159 | # Return coverage information and corpus of inputs. 160 | return (self.coverage, self.corpus) 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Program Analysis with Chiron 2 | 3 | A framework to teach program analysis, verification, and testing in a graduate-level course. 4 | 5 | ``` 6 | ░█████╗░██╗░░██╗██╗██████╗░░█████╗░███╗░░██╗ 7 | ██╔══██╗██║░░██║██║██╔══██╗██╔══██╗████╗░██║ 8 | ██║░░╚═╝███████║██║██████╔╝██║░░██║██╔██╗██║ 9 | ██║░░██╗██╔══██║██║██╔══██╗██║░░██║██║╚████║ 10 | ╚█████╔╝██║░░██║██║██║░░██║╚█████╔╝██║░╚███║ 11 | ░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░╚═╝░╚════╝░╚═╝░░╚══╝ 12 | ``` 13 | [![Architecture Diagram](./assets/Architecture_Digram.png)](./assets/Architecture_Digram.png) 14 | 15 | ## Video Demo 16 | 17 | Fuzzer Demo in Chiron Framework. Click the image below 18 | 19 | Alternate Text 20 | 21 | - [Some nice words in WSS' 2023, IIT Delhi about Chiron Framework](https://www.linkedin.com/posts/ashupdsce_wss-wss2023-iitd-activity-7150851909581463553-bJ6-?utm_source=share&utm_medium=member_desktop) 22 | - [ASE 2023 Conference Page](https://conf.researchr.org/details/ase-2023/ase-2023-papers/117/An-Integrated-Program-Analysis-Framework-for-Graduate-Courses-in-Programming-Language) 23 | - [Read our research paper here](https://ieeexplore.ieee.org/document/10298417) 24 | 25 | ## Citation 26 | 27 | If you want to cite this work, you may use this. 28 | 29 | ``` 30 | @INPROCEEDINGS{ase_2023_chiron, 31 | author={Chatterjee, Prantik and Kalita, Pankaj Kumar and Lahiri, Sumit and Muduli, Sujit Kumar and Singh, Vishal and Takhar, Gourav and Roy, Subhajit}, 32 | booktitle={2023 38th IEEE/ACM International Conference on Automated Software Engineering (ASE)}, 33 | title={An Integrated Program Analysis Framework for Graduate Courses in Programming Languages and Software Engineering}, 34 | year={2023}, 35 | volume={}, 36 | number={}, 37 | pages={598-610}, 38 | keywords={Surveys;Computer languages;Program processors;Software algorithms;Software systems;Task analysis;Engines;program analysis verification and testing;programming languages;software engineering;graduate level course;education}, 39 | doi={10.1109/ASE56229.2023.00101}} 40 | ``` 41 | ### Installing Dependencies 42 | 43 | ```bash 44 | $ pip install antlr4-python3-runtime==4.7.2 networkx z3-solver numpy 45 | $ sudo apt-get install python3-tk 46 | ``` 47 | 48 | ### Generating the ANTLR files. 49 | 50 | The `antlr` files need to be rebuilt if any changes are made to the `tlang.g4` file or when installing Chiron for the first time. 51 | We use a visitor pattern to generate the AST from parsing. 52 | 53 | ``` 54 | $ cd ChironCore/turtparse 55 | $ java -cp ../extlib/antlr-4.7.2-complete.jar org.antlr.v4.Tool \ 56 | -Dlanguage=Python3 -visitor -no-listener tlang.g4 57 | ``` 58 | 59 | ### Running an example 60 | 61 | The main directory for source files is `ChironCore`. We have examples of the turtle programs in `examples` folder. 62 | To pass parameters (input params) for running a turtle program, use the `-d` flag. Pass the parameters as a python dictionary. 63 | 64 | ```bash 65 | $ cd ChironCore 66 | $ ./chiron.py -r ./example/example1.tl -d '{":x": 20, "y": 30, ":z": 20, ":p": 40}' 67 | ``` 68 | 69 | ### See help for other command line options 70 | 71 | ```bash 72 | $ python3 chiron.py --help 73 | 74 | 75 | ░█████╗░██╗░░██╗██╗██████╗░░█████╗░███╗░░██╗ 76 | ██╔══██╗██║░░██║██║██╔══██╗██╔══██╗████╗░██║ 77 | ██║░░╚═╝███████║██║██████╔╝██║░░██║██╔██╗██║ 78 | ██║░░██╗██╔══██║██║██╔══██╗██║░░██║██║╚████║ 79 | ╚█████╔╝██║░░██║██║██║░░██║╚█████╔╝██║░╚███║ 80 | ░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░╚═╝░╚════╝░╚═╝░░╚══╝ 81 | 82 | 83 | Chiron v1.0.1 84 | ------------ 85 | usage: chiron.py [-h] [-p] [-r] [-gr] [-b] [-z] [-t TIMEOUT] [-d PARAMS] [-c CONSTPARAMS] [-se] [-ai] [-dfa] [-sbfl] 86 | [-bg BUGGY] [-vars INPUTVARSLIST] [-nt NTESTS] [-pop POPSIZE] [-cp CXPB] [-mp MUTPB] [-ng NGEN] 87 | [-vb VERBOSE] 88 | progfl 89 | 90 | Program Analysis Framework for ChironLang Programs. 91 | 92 | positional arguments: 93 | progfl 94 | 95 | options: 96 | -h, --help show this help message and exit 97 | -p, --ir pretty printing the IR of a Chiron program to stdout (terminal) 98 | -r, --run execute Chiron program, the figure/shapes the turle draws is shown in a UI. 99 | -gr, --fuzzer_gen_rand 100 | Generate random input seeds for the fuzzer before fuzzing starts. 101 | -b, --bin load binary IR of a Chiron program 102 | -z, --fuzz Run fuzzer on a Chiron program (seed values with '-d' or '--params' flag needed.) 103 | -t TIMEOUT, --timeout TIMEOUT 104 | Timeout Parameter for Analysis (in secs). This is the total timeout. 105 | -d PARAMS, --params PARAMS 106 | pass variable values to Chiron program in python dictionary format 107 | -c CONSTPARAMS, --constparams CONSTPARAMS 108 | pass variable(for which you have to find values using circuit equivalence) values to Chiron program 109 | in python dictionary format 110 | -se, --symbolicExecution 111 | Run Symbolic Execution on a Chiron program (seed values with '-d' or '--params' flag needed) to 112 | generate test cases along all possible paths. 113 | -ai, --abstractInterpretation 114 | Run abstract interpretation on a Chiron Program. 115 | -dfa, --dataFlowAnalysis 116 | Run data flow analysis using worklist algorithm on a Chiron Program. 117 | -sbfl, --SBFL Run Spectrum-basedFault localizer on Chiron program 118 | -bg BUGGY, --buggy BUGGY 119 | buggy Chiron program path 120 | -vars INPUTVARSLIST, --inputVarsList INPUTVARSLIST 121 | A list of input variables of given Chiron program 122 | -nt NTESTS, --ntests NTESTS 123 | number of tests to generate 124 | -pop POPSIZE, --popsize POPSIZE 125 | population size for Genetic Algorithm. 126 | -cp CXPB, --cxpb CXPB 127 | cross-over probability 128 | -mp MUTPB, --mutpb MUTPB 129 | mutation probability 130 | -ng NGEN, --ngen NGEN 131 | number of times Genetic Algorithm iterates 132 | -vb VERBOSE, --verbose VERBOSE 133 | To display computation to Console 134 | 135 | ``` 136 | -------------------------------------------------------------------------------- /ChironCore/ChironAST/builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # ChironLang Abstract Syntax Tree Builder 4 | 5 | import os 6 | import sys 7 | sys.path.insert(0, os.path.join("..", "turtparse")) 8 | 9 | from turtparse.tlangParser import tlangParser 10 | from turtparse.tlangVisitor import tlangVisitor 11 | 12 | from ChironAST import ChironAST 13 | 14 | 15 | class astGenPass(tlangVisitor): 16 | 17 | def __init__(self): 18 | self.repeatInstrCount = 0 # keeps count for no of 'repeat' instructions 19 | 20 | def visitStart(self, ctx:tlangParser.StartContext): 21 | stmtList = self.visit(ctx.instruction_list()) 22 | return stmtList 23 | 24 | def visitInstruction_list(self, ctx:tlangParser.Instruction_listContext): 25 | instrList = [] 26 | for instr in ctx.instruction(): 27 | instrList.extend(self.visit(instr)) 28 | 29 | return instrList 30 | 31 | def visitStrict_ilist(self, ctx:tlangParser.Strict_ilistContext): 32 | # TODO: code refactoring. visitInstruction_list and visitStrict_ilist have same body 33 | instrList = [] 34 | for instr in ctx.instruction(): 35 | visvalue = self.visit(instr) 36 | instrList.extend(visvalue) 37 | 38 | return instrList 39 | 40 | 41 | def visitAssignment(self, ctx:tlangParser.AssignmentContext): 42 | lval = ChironAST.Var(ctx.VAR().getText()) 43 | rval = self.visit(ctx.expression()) 44 | return [(ChironAST.AssignmentCommand(lval, rval), 1)] 45 | 46 | 47 | def visitIfConditional(self, ctx:tlangParser.IfConditionalContext): 48 | condObj = ChironAST.ConditionCommand(self.visit(ctx.condition())) 49 | thenInstrList = self.visit(ctx.strict_ilist()) 50 | return [(condObj, len(thenInstrList) + 1)] + thenInstrList 51 | 52 | def visitIfElseConditional(self, ctx:tlangParser.IfElseConditionalContext): 53 | condObj = ChironAST.ConditionCommand(self.visit(ctx.condition())) 54 | thenInstrList = self.visit(ctx.strict_ilist(0)) 55 | elseInstrList = self.visit(ctx.strict_ilist(1)) 56 | jumpOverElseBlock = [(ChironAST.ConditionCommand(ChironAST.BoolFalse()), len(elseInstrList) + 1)] 57 | return [(condObj, len(thenInstrList) + 2)] + thenInstrList + jumpOverElseBlock + elseInstrList 58 | 59 | def visitGotoCommand(self, ctx:tlangParser.GotoCommandContext): 60 | xcor = self.visit(ctx.expression(0)) 61 | ycor = self.visit(ctx.expression(1)) 62 | return [(ChironAST.GotoCommand(xcor, ycor), 1)] 63 | 64 | # Visit a parse tree produced by tlangParser#unaryExpr. 65 | def visitUnaryExpr(self, ctx:tlangParser.UnaryExprContext): 66 | expr1 = self.visit(ctx.expression()) 67 | if ctx.unaryArithOp().MINUS(): 68 | return ChironAST.UMinus(expr1) 69 | 70 | return self.visitChildren(ctx) 71 | 72 | 73 | # Visit a parse tree produced by tlangParser#addExpr. 74 | def visitAddExpr(self, ctx:tlangParser.AddExprContext): 75 | left = self.visit(ctx.expression(0)) 76 | right = self.visit(ctx.expression(1)) 77 | if ctx.additive().PLUS(): 78 | return ChironAST.Sum(left, right) 79 | elif ctx.additive().MINUS(): 80 | return ChironAST.Diff(left, right) 81 | 82 | 83 | # Visit a parse tree produced by tlangParser#mulExpr. 84 | def visitMulExpr(self, ctx:tlangParser.MulExprContext): 85 | left = self.visit(ctx.expression(0)) 86 | right = self.visit(ctx.expression(1)) 87 | if ctx.multiplicative().MUL(): 88 | return ChironAST.Mult(left, right) 89 | elif ctx.multiplicative().DIV(): 90 | return ChironAST.Div(left, right) 91 | 92 | 93 | # Visit a parse tree produced by tlangParser#parenExpr. 94 | def visitParenExpr(self, ctx:tlangParser.ParenExprContext): 95 | return self.visit(ctx.expression()) 96 | 97 | 98 | def visitCondition(self, ctx:tlangParser.ConditionContext): 99 | if ctx.PENCOND(): 100 | return ChironAST.PenStatus(); 101 | 102 | if ctx.NOT(): 103 | expr1 = self.visit(ctx.condition(0)) 104 | return ChironAST.NOT(expr1) 105 | 106 | 107 | if ctx.logicOp(): 108 | expr1 = self.visit(ctx.condition(0)) 109 | expr2 = self.visit(ctx.condition(1)) 110 | logicOpCtx = ctx.logicOp() 111 | 112 | if logicOpCtx.AND(): 113 | return ChironAST.AND(expr1, expr2) 114 | elif logicOpCtx.OR(): 115 | return ChironAST.OR(expr1, expr2) 116 | 117 | 118 | if ctx.binCondOp(): 119 | expr1 = self.visit(ctx.expression(0)) 120 | expr2 = self.visit(ctx.expression(1)) 121 | binOpCtx = ctx.binCondOp() 122 | 123 | if binOpCtx.LT(): 124 | return ChironAST.LT(expr1, expr2) 125 | elif binOpCtx.GT(): 126 | return ChironAST.GT(expr1, expr2) 127 | elif binOpCtx.EQ(): 128 | return ChironAST.EQ(expr1, expr2) 129 | elif binOpCtx.NEQ(): 130 | return ChironAST.NEQ(expr1, expr2) 131 | elif binOpCtx.LTE(): 132 | return ChironAST.LTE(expr1, expr2) 133 | elif binOpCtx.GTE(): 134 | return ChironAST.GTE(expr1, expr2) 135 | 136 | if ctx.condition(): 137 | # condition is inside paranthesis 138 | return self.visit(ctx.condition(0)) 139 | 140 | return self.visitChildren(ctx) 141 | 142 | def visitValue(self, ctx:tlangParser.ValueContext): 143 | if ctx.NUM(): 144 | return ChironAST.Num(ctx.NUM().getText()) 145 | elif ctx.VAR(): 146 | return ChironAST.Var(ctx.VAR().getText()) 147 | 148 | def visitLoop(self, ctx:tlangParser.LoopContext): 149 | # insert counter variable in IR for tracking repeat count 150 | self.repeatInstrCount += 1 151 | repeatNum = self.visit(ctx.value()) 152 | counterVar = ChironAST.Var(":__rep_counter_" + str(self.repeatInstrCount)) 153 | counterVarInitInstr = ChironAST.AssignmentCommand(counterVar, repeatNum) 154 | constZero = ChironAST.Num(0) 155 | constOne = ChironAST.Num(1) 156 | loopCond = ChironAST.ConditionCommand(ChironAST.GT(counterVar, constZero)) 157 | counterVarDecrInstr = ChironAST.AssignmentCommand(counterVar, ChironAST.Diff(counterVar, constOne)) 158 | 159 | thenInstrList = [] 160 | for instr in ctx.strict_ilist().instruction(): 161 | temp = self.visit(instr) 162 | thenInstrList.extend(temp) 163 | 164 | boolFalse = ChironAST.ConditionCommand(ChironAST.BoolFalse()) 165 | return [(counterVarInitInstr, 1), (loopCond, len(thenInstrList) + 3)] + thenInstrList +\ 166 | [(counterVarDecrInstr, 1), (boolFalse, -len(thenInstrList) - 2)] 167 | 168 | def visitMoveCommand(self, ctx:tlangParser.MoveCommandContext): 169 | mvcommand = ctx.moveOp().getText() 170 | mvexpr = self.visit(ctx.expression()) 171 | return [(ChironAST.MoveCommand(mvcommand, mvexpr), 1)] 172 | 173 | def visitPenCommand(self, ctx:tlangParser.PenCommandContext): 174 | return [(ChironAST.PenCommand(ctx.getText()), 1)] 175 | -------------------------------------------------------------------------------- /ChironCore/turtparse/tlangLexer.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | 'if' 4 | '[' 5 | ']' 6 | 'else' 7 | 'repeat' 8 | 'goto' 9 | '(' 10 | ',' 11 | ')' 12 | '=' 13 | 'forward' 14 | 'backward' 15 | 'left' 16 | 'right' 17 | 'penup' 18 | 'pendown' 19 | 'pause' 20 | '+' 21 | '-' 22 | '*' 23 | '/' 24 | 'pendown?' 25 | '<' 26 | '>' 27 | '==' 28 | '!=' 29 | '<=' 30 | '>=' 31 | '&&' 32 | '||' 33 | '!' 34 | null 35 | null 36 | null 37 | null 38 | 39 | token symbolic names: 40 | null 41 | null 42 | null 43 | null 44 | null 45 | null 46 | null 47 | null 48 | null 49 | null 50 | null 51 | null 52 | null 53 | null 54 | null 55 | null 56 | null 57 | null 58 | PLUS 59 | MINUS 60 | MUL 61 | DIV 62 | PENCOND 63 | LT 64 | GT 65 | EQ 66 | NEQ 67 | LTE 68 | GTE 69 | AND 70 | OR 71 | NOT 72 | NUM 73 | VAR 74 | NAME 75 | Whitespace 76 | 77 | rule names: 78 | T__0 79 | T__1 80 | T__2 81 | T__3 82 | T__4 83 | T__5 84 | T__6 85 | T__7 86 | T__8 87 | T__9 88 | T__10 89 | T__11 90 | T__12 91 | T__13 92 | T__14 93 | T__15 94 | T__16 95 | PLUS 96 | MINUS 97 | MUL 98 | DIV 99 | PENCOND 100 | LT 101 | GT 102 | EQ 103 | NEQ 104 | LTE 105 | GTE 106 | AND 107 | OR 108 | NOT 109 | NUM 110 | VAR 111 | NAME 112 | Whitespace 113 | 114 | channel names: 115 | DEFAULT_TOKEN_CHANNEL 116 | HIDDEN 117 | 118 | mode names: 119 | DEFAULT_MODE 120 | 121 | atn: 122 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 37, 219, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 6, 33, 196, 10, 33, 13, 33, 14, 33, 197, 3, 34, 3, 34, 3, 34, 7, 34, 203, 10, 34, 12, 34, 14, 34, 206, 11, 34, 3, 35, 6, 35, 209, 10, 35, 13, 35, 14, 35, 210, 3, 36, 6, 36, 214, 10, 36, 13, 36, 14, 36, 215, 3, 36, 3, 36, 2, 2, 37, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 3, 2, 7, 3, 2, 50, 59, 5, 2, 67, 92, 97, 97, 99, 124, 5, 2, 50, 59, 67, 92, 99, 124, 4, 2, 67, 92, 99, 124, 5, 2, 11, 12, 15, 15, 34, 34, 2, 222, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 3, 73, 3, 2, 2, 2, 5, 76, 3, 2, 2, 2, 7, 78, 3, 2, 2, 2, 9, 80, 3, 2, 2, 2, 11, 85, 3, 2, 2, 2, 13, 92, 3, 2, 2, 2, 15, 97, 3, 2, 2, 2, 17, 99, 3, 2, 2, 2, 19, 101, 3, 2, 2, 2, 21, 103, 3, 2, 2, 2, 23, 105, 3, 2, 2, 2, 25, 113, 3, 2, 2, 2, 27, 122, 3, 2, 2, 2, 29, 127, 3, 2, 2, 2, 31, 133, 3, 2, 2, 2, 33, 139, 3, 2, 2, 2, 35, 147, 3, 2, 2, 2, 37, 153, 3, 2, 2, 2, 39, 155, 3, 2, 2, 2, 41, 157, 3, 2, 2, 2, 43, 159, 3, 2, 2, 2, 45, 161, 3, 2, 2, 2, 47, 170, 3, 2, 2, 2, 49, 172, 3, 2, 2, 2, 51, 174, 3, 2, 2, 2, 53, 177, 3, 2, 2, 2, 55, 180, 3, 2, 2, 2, 57, 183, 3, 2, 2, 2, 59, 186, 3, 2, 2, 2, 61, 189, 3, 2, 2, 2, 63, 192, 3, 2, 2, 2, 65, 195, 3, 2, 2, 2, 67, 199, 3, 2, 2, 2, 69, 208, 3, 2, 2, 2, 71, 213, 3, 2, 2, 2, 73, 74, 7, 107, 2, 2, 74, 75, 7, 104, 2, 2, 75, 4, 3, 2, 2, 2, 76, 77, 7, 93, 2, 2, 77, 6, 3, 2, 2, 2, 78, 79, 7, 95, 2, 2, 79, 8, 3, 2, 2, 2, 80, 81, 7, 103, 2, 2, 81, 82, 7, 110, 2, 2, 82, 83, 7, 117, 2, 2, 83, 84, 7, 103, 2, 2, 84, 10, 3, 2, 2, 2, 85, 86, 7, 116, 2, 2, 86, 87, 7, 103, 2, 2, 87, 88, 7, 114, 2, 2, 88, 89, 7, 103, 2, 2, 89, 90, 7, 99, 2, 2, 90, 91, 7, 118, 2, 2, 91, 12, 3, 2, 2, 2, 92, 93, 7, 105, 2, 2, 93, 94, 7, 113, 2, 2, 94, 95, 7, 118, 2, 2, 95, 96, 7, 113, 2, 2, 96, 14, 3, 2, 2, 2, 97, 98, 7, 42, 2, 2, 98, 16, 3, 2, 2, 2, 99, 100, 7, 46, 2, 2, 100, 18, 3, 2, 2, 2, 101, 102, 7, 43, 2, 2, 102, 20, 3, 2, 2, 2, 103, 104, 7, 63, 2, 2, 104, 22, 3, 2, 2, 2, 105, 106, 7, 104, 2, 2, 106, 107, 7, 113, 2, 2, 107, 108, 7, 116, 2, 2, 108, 109, 7, 121, 2, 2, 109, 110, 7, 99, 2, 2, 110, 111, 7, 116, 2, 2, 111, 112, 7, 102, 2, 2, 112, 24, 3, 2, 2, 2, 113, 114, 7, 100, 2, 2, 114, 115, 7, 99, 2, 2, 115, 116, 7, 101, 2, 2, 116, 117, 7, 109, 2, 2, 117, 118, 7, 121, 2, 2, 118, 119, 7, 99, 2, 2, 119, 120, 7, 116, 2, 2, 120, 121, 7, 102, 2, 2, 121, 26, 3, 2, 2, 2, 122, 123, 7, 110, 2, 2, 123, 124, 7, 103, 2, 2, 124, 125, 7, 104, 2, 2, 125, 126, 7, 118, 2, 2, 126, 28, 3, 2, 2, 2, 127, 128, 7, 116, 2, 2, 128, 129, 7, 107, 2, 2, 129, 130, 7, 105, 2, 2, 130, 131, 7, 106, 2, 2, 131, 132, 7, 118, 2, 2, 132, 30, 3, 2, 2, 2, 133, 134, 7, 114, 2, 2, 134, 135, 7, 103, 2, 2, 135, 136, 7, 112, 2, 2, 136, 137, 7, 119, 2, 2, 137, 138, 7, 114, 2, 2, 138, 32, 3, 2, 2, 2, 139, 140, 7, 114, 2, 2, 140, 141, 7, 103, 2, 2, 141, 142, 7, 112, 2, 2, 142, 143, 7, 102, 2, 2, 143, 144, 7, 113, 2, 2, 144, 145, 7, 121, 2, 2, 145, 146, 7, 112, 2, 2, 146, 34, 3, 2, 2, 2, 147, 148, 7, 114, 2, 2, 148, 149, 7, 99, 2, 2, 149, 150, 7, 119, 2, 2, 150, 151, 7, 117, 2, 2, 151, 152, 7, 103, 2, 2, 152, 36, 3, 2, 2, 2, 153, 154, 7, 45, 2, 2, 154, 38, 3, 2, 2, 2, 155, 156, 7, 47, 2, 2, 156, 40, 3, 2, 2, 2, 157, 158, 7, 44, 2, 2, 158, 42, 3, 2, 2, 2, 159, 160, 7, 49, 2, 2, 160, 44, 3, 2, 2, 2, 161, 162, 7, 114, 2, 2, 162, 163, 7, 103, 2, 2, 163, 164, 7, 112, 2, 2, 164, 165, 7, 102, 2, 2, 165, 166, 7, 113, 2, 2, 166, 167, 7, 121, 2, 2, 167, 168, 7, 112, 2, 2, 168, 169, 7, 65, 2, 2, 169, 46, 3, 2, 2, 2, 170, 171, 7, 62, 2, 2, 171, 48, 3, 2, 2, 2, 172, 173, 7, 64, 2, 2, 173, 50, 3, 2, 2, 2, 174, 175, 7, 63, 2, 2, 175, 176, 7, 63, 2, 2, 176, 52, 3, 2, 2, 2, 177, 178, 7, 35, 2, 2, 178, 179, 7, 63, 2, 2, 179, 54, 3, 2, 2, 2, 180, 181, 7, 62, 2, 2, 181, 182, 7, 63, 2, 2, 182, 56, 3, 2, 2, 2, 183, 184, 7, 64, 2, 2, 184, 185, 7, 63, 2, 2, 185, 58, 3, 2, 2, 2, 186, 187, 7, 40, 2, 2, 187, 188, 7, 40, 2, 2, 188, 60, 3, 2, 2, 2, 189, 190, 7, 126, 2, 2, 190, 191, 7, 126, 2, 2, 191, 62, 3, 2, 2, 2, 192, 193, 7, 35, 2, 2, 193, 64, 3, 2, 2, 2, 194, 196, 9, 2, 2, 2, 195, 194, 3, 2, 2, 2, 196, 197, 3, 2, 2, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 66, 3, 2, 2, 2, 199, 200, 7, 60, 2, 2, 200, 204, 9, 3, 2, 2, 201, 203, 9, 4, 2, 2, 202, 201, 3, 2, 2, 2, 203, 206, 3, 2, 2, 2, 204, 202, 3, 2, 2, 2, 204, 205, 3, 2, 2, 2, 205, 68, 3, 2, 2, 2, 206, 204, 3, 2, 2, 2, 207, 209, 9, 5, 2, 2, 208, 207, 3, 2, 2, 2, 209, 210, 3, 2, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 70, 3, 2, 2, 2, 212, 214, 9, 6, 2, 2, 213, 212, 3, 2, 2, 2, 214, 215, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 218, 8, 36, 2, 2, 218, 72, 3, 2, 2, 2, 7, 2, 197, 204, 210, 215, 3, 8, 2, 2] -------------------------------------------------------------------------------- /ChironCore/sExecution.py: -------------------------------------------------------------------------------- 1 | # Test case generation with the help of Symbolic Execution 2 | import sys 3 | import time 4 | from z3 import * 5 | from interpreter import * 6 | # sys.path.insert(0, '../Submission/') 7 | 8 | from interfaces.sExecutionInterface import * 9 | import json 10 | 11 | def genPC(pc,pcEval, flipPC): 12 | # print("pc and pcEval") 13 | # print(pcEval) 14 | # print(flipPC) 15 | while len(flipPC)!=0: 16 | if flipPC[len(flipPC)-1]==1: 17 | flipPC = flipPC[:-1] 18 | pc = pc[:-1] 19 | pcEval = pcEval[:-1] 20 | continue 21 | pcEval[len(flipPC)-1] = not pcEval[len(flipPC)-1] 22 | flipPC[len(flipPC)-1] = 1 23 | # print(flipPC) 24 | # print(pc,pcEval,flipPC) 25 | return pc, pcEval, flipPC, False 26 | # print(pc,pcEval,flipPC) 27 | return None, None, None, True 28 | 29 | def generateConditions(s,pcIndex,pc,params,coverage,ir,pcEval): 30 | print("\n\n For Parameters:",params) 31 | s.initProgramContext(params) 32 | s.resetSolver() 33 | for i in range(0,len(coverage)): 34 | if pcIndex>=len(pc): 35 | break 36 | irIndexPC = pc[pcIndex] if len(pc)!=0 else -1 37 | irIndexCoverage = coverage[i] 38 | stmt, tgt = ir[irIndexCoverage] 39 | if irIndexPC==irIndexCoverage or isinstance(ir[irIndexCoverage][0], ChironAST.ConditionCommand): 40 | if irIndexPC==irIndexCoverage: 41 | encPC = s.handleCondition(stmt,not pcEval[pcIndex]) 42 | else: 43 | if str(ir[irIndexCoverage][0])=="False": 44 | encPC = s.handleCondition(stmt,True) 45 | else: 46 | encPC = s.handleCondition(stmt,False) 47 | print("stmt ",stmt) 48 | if isinstance(stmt.cond, ChironAST.NEQ): 49 | if str(stmt.cond.lexpr).startswith(":__rep_counter_"): 50 | exec("s.s.add(s.z3Vars.%s>=0)"%str(stmt.cond.lexpr).replace(":","")) 51 | print(stmt, irIndexCoverage, ir[irIndexCoverage][0]) 52 | print("symbEnc", vars(s.z3Vars),"\n") 53 | print("assertions", (s.s.assertions()),"\n") 54 | # if pcIndex=len(pc): 57 | break 58 | 59 | else: 60 | s.eval(stmt) 61 | print(stmt) 62 | print("symbEnc else", vars(s.z3Vars),"\n") 63 | return pc, pcIndex 64 | 65 | 66 | def generateEncryption(s,pcIndex,pc,params,coverage,ir,pcEval): 67 | print("\n\n For Parameters:",params) 68 | s.initProgramContext(params) 69 | s.resetSolver() 70 | for i in range(0,len(coverage)): 71 | irIndexPC = pc[pcIndex] if len(pc)!=0 else -1 72 | irIndexCoverage = coverage[i] 73 | stmt, tgt = ir[irIndexCoverage] 74 | if irIndexPC==irIndexCoverage or isinstance(ir[irIndexCoverage][0], ChironAST.ConditionCommand): 75 | if irIndexPC==irIndexCoverage: 76 | encPC = s.handleCondition(stmt,not pcEval[pcIndex]) 77 | else: 78 | if str(ir[irIndexCoverage][0])=="False": 79 | encPC = s.handleCondition(stmt,True) 80 | else: 81 | encPC = s.handleCondition(stmt,False) 82 | print("stmt ",stmt) 83 | if isinstance(stmt.cond, ChironAST.NEQ): 84 | if str(stmt.cond.lexpr).startswith(":__rep_counter_"): 85 | exec("s.s.add(s.z3Vars.%s>=0)"%str(stmt.cond.lexpr).replace(":","")) 86 | print(stmt, irIndexCoverage, ir[irIndexCoverage][0]) 87 | print("symbEnc", vars(s.z3Vars),"\n") 88 | print("assertions", (s.s.assertions()),"\n") 89 | if pcIndex {params}") 109 | for k in constparams: 110 | params[k]=constparams[k] 111 | # Initial Seed values from user. 112 | # temp_input = InputObject(data=params) 113 | start_time = time.time() 114 | # symbolic execution ends at this timestamp. 115 | endTime = time.time() + timeLimit 116 | flipPC = [] 117 | s = z3Solver(irHandler.ir) 118 | s.initProgramContext(params) 119 | # The maximum time for symbolic execution of the 120 | # program must be less than end time. 121 | rnd1=0 122 | res = "sat" 123 | tmplist = [] 124 | testData = {} 125 | while time.time() <= endTime: 126 | if str(res)=="sat": 127 | # print("Testcase: ",rnd1) 128 | rnd1+=1 129 | coverage = [] # coverage for current path 130 | pc = [] 131 | pcEval = [] 132 | inptr = ConcreteInterpreter(irHandler, None) 133 | inptr.pc = 0 134 | terminated = False 135 | inptr.initProgramContext(params) 136 | while time.time() <= endTime : 137 | coverage.append(inptr.pc) 138 | stmt, tgt = irHandler.ir[inptr.pc] 139 | if isinstance(stmt, ChironAST.ConditionCommand): 140 | pc.append(inptr.pc) 141 | terminated = inptr.interpret() 142 | if isinstance(stmt, ChironAST.ConditionCommand): 143 | pcEval.append(inptr.cond_eval) 144 | if terminated: 145 | break 146 | # print("pc coverage",pc,coverage) 147 | if time.time() > endTime: 148 | break 149 | flipPC += [0 for i in range(len(flipPC),len(pc))] 150 | # print(flipPC) 151 | if str(pcEval) not in tmplist: 152 | tmplist.append(pcEval) 153 | # print("Coverage: ",coverage,"\nParameters: ",params,"\n\n") 154 | s.initProgramContext(params) 155 | s.resetSolver() 156 | pcIndex=0 157 | # print("testdata ",testData,pc,pcEval,coverage) 158 | pc, pcIndex =generateEncryption(s,pcIndex,pc,params,coverage,irHandler.ir,pcEval) 159 | if str(res)=="sat": 160 | data = {} 161 | params1={} 162 | for k in params: 163 | params1[k[1:]]=params[k] 164 | data['params']=str(params1) 165 | data['constparams']=str(list(constparams.keys())) 166 | data['coverage']=str(coverage) 167 | data['pc']=str(pc) 168 | data['pcEval']=str(pcEval) 169 | symbEnc1={} 170 | symbEnc = vars(s.z3Vars) 171 | for k in symbEnc: 172 | symbEnc1[k]=str(symbEnc[k]) 173 | data['symbEnc']=str(symbEnc1) 174 | data['constraints']=str(z3.simplify(z3.And(s.s.assertions()))) 175 | testData[rnd1] = data 176 | print("pc before ",pc,pcEval,flipPC) 177 | pc, pcEval, flipPC, done = genPC(pc, pcEval, flipPC) 178 | print(s.s.assertions()) 179 | print("pc after ",pc,pcEval,flipPC) 180 | if done: 181 | print("done break\n\n") 182 | break 183 | pcIndex=0 184 | s.initProgramContext(params) 185 | s.resetSolver() 186 | pc, pcIndex =generateConditions(s,pcIndex,pc,params,coverage,irHandler.ir,pcEval) 187 | res = s.s.check() 188 | print(s.s.assertions()) 189 | print("res ",res) 190 | if str(res)=="sat": 191 | m = s.s.model() 192 | print("model printing",m,type(m)) 193 | for x in m: 194 | for key in params: 195 | if ":"+str(x) == key: 196 | params[key] = m[x].as_long() 197 | print(params,"end") 198 | json_obj = json.dumps(testData,indent=4) 199 | print(json_obj) 200 | file1 = open("../Submission/testData.json","w+") 201 | file1.write(json_obj) 202 | file1.close() 203 | 204 | if time.time() >= endTime: 205 | print(f" Program took too long to execute. Terminated") 206 | else: 207 | print("All possible paths covered.") 208 | # exit() 209 | pass 210 | -------------------------------------------------------------------------------- /ChironCore/turtparse/tlangLexer.py: -------------------------------------------------------------------------------- 1 | # Generated from tlang.g4 by ANTLR 4.7.2 2 | from antlr4 import * 3 | from io import StringIO 4 | from typing.io import TextIO 5 | import sys 6 | 7 | 8 | def serializedATN(): 9 | with StringIO() as buf: 10 | buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2%") 11 | buf.write("\u00db\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") 12 | buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") 13 | buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23") 14 | buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30") 15 | buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36") 16 | buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\3\2\3") 17 | buf.write("\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6") 18 | buf.write("\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\t\3\t\3") 19 | buf.write("\n\3\n\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3") 20 | buf.write("\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3\16") 21 | buf.write("\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20") 22 | buf.write("\3\20\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22") 23 | buf.write("\3\22\3\22\3\22\3\22\3\23\3\23\3\24\3\24\3\25\3\25\3\26") 24 | buf.write("\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\27\3\30") 25 | buf.write("\3\30\3\31\3\31\3\32\3\32\3\32\3\33\3\33\3\33\3\34\3\34") 26 | buf.write("\3\34\3\35\3\35\3\35\3\36\3\36\3\36\3\37\3\37\3\37\3 ") 27 | buf.write("\3 \3!\6!\u00c4\n!\r!\16!\u00c5\3\"\3\"\3\"\7\"\u00cb") 28 | buf.write("\n\"\f\"\16\"\u00ce\13\"\3#\6#\u00d1\n#\r#\16#\u00d2\3") 29 | buf.write("$\6$\u00d6\n$\r$\16$\u00d7\3$\3$\2\2%\3\3\5\4\7\5\t\6") 30 | buf.write("\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20") 31 | buf.write("\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65") 32 | buf.write("\34\67\359\36;\37= ?!A\"C#E$G%\3\2\7\3\2\62;\5\2C\\aa") 33 | buf.write("c|\5\2\62;C\\c|\4\2C\\c|\5\2\13\f\17\17\"\"\2\u00de\2") 34 | buf.write("\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3") 35 | buf.write("\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2") 36 | buf.write("\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2") 37 | buf.write("\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%") 38 | buf.write("\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2") 39 | buf.write("\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67") 40 | buf.write("\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2") 41 | buf.write("A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\3I\3\2\2\2") 42 | buf.write("\5L\3\2\2\2\7N\3\2\2\2\tP\3\2\2\2\13U\3\2\2\2\r\\\3\2") 43 | buf.write("\2\2\17a\3\2\2\2\21c\3\2\2\2\23e\3\2\2\2\25g\3\2\2\2\27") 44 | buf.write("i\3\2\2\2\31q\3\2\2\2\33z\3\2\2\2\35\177\3\2\2\2\37\u0085") 45 | buf.write("\3\2\2\2!\u008b\3\2\2\2#\u0093\3\2\2\2%\u0099\3\2\2\2") 46 | buf.write("\'\u009b\3\2\2\2)\u009d\3\2\2\2+\u009f\3\2\2\2-\u00a1") 47 | buf.write("\3\2\2\2/\u00aa\3\2\2\2\61\u00ac\3\2\2\2\63\u00ae\3\2") 48 | buf.write("\2\2\65\u00b1\3\2\2\2\67\u00b4\3\2\2\29\u00b7\3\2\2\2") 49 | buf.write(";\u00ba\3\2\2\2=\u00bd\3\2\2\2?\u00c0\3\2\2\2A\u00c3\3") 50 | buf.write("\2\2\2C\u00c7\3\2\2\2E\u00d0\3\2\2\2G\u00d5\3\2\2\2IJ") 51 | buf.write("\7k\2\2JK\7h\2\2K\4\3\2\2\2LM\7]\2\2M\6\3\2\2\2NO\7_\2") 52 | buf.write("\2O\b\3\2\2\2PQ\7g\2\2QR\7n\2\2RS\7u\2\2ST\7g\2\2T\n\3") 53 | buf.write("\2\2\2UV\7t\2\2VW\7g\2\2WX\7r\2\2XY\7g\2\2YZ\7c\2\2Z[") 54 | buf.write("\7v\2\2[\f\3\2\2\2\\]\7i\2\2]^\7q\2\2^_\7v\2\2_`\7q\2") 55 | buf.write("\2`\16\3\2\2\2ab\7*\2\2b\20\3\2\2\2cd\7.\2\2d\22\3\2\2") 56 | buf.write("\2ef\7+\2\2f\24\3\2\2\2gh\7?\2\2h\26\3\2\2\2ij\7h\2\2") 57 | buf.write("jk\7q\2\2kl\7t\2\2lm\7y\2\2mn\7c\2\2no\7t\2\2op\7f\2\2") 58 | buf.write("p\30\3\2\2\2qr\7d\2\2rs\7c\2\2st\7e\2\2tu\7m\2\2uv\7y") 59 | buf.write("\2\2vw\7c\2\2wx\7t\2\2xy\7f\2\2y\32\3\2\2\2z{\7n\2\2{") 60 | buf.write("|\7g\2\2|}\7h\2\2}~\7v\2\2~\34\3\2\2\2\177\u0080\7t\2") 61 | buf.write("\2\u0080\u0081\7k\2\2\u0081\u0082\7i\2\2\u0082\u0083\7") 62 | buf.write("j\2\2\u0083\u0084\7v\2\2\u0084\36\3\2\2\2\u0085\u0086") 63 | buf.write("\7r\2\2\u0086\u0087\7g\2\2\u0087\u0088\7p\2\2\u0088\u0089") 64 | buf.write("\7w\2\2\u0089\u008a\7r\2\2\u008a \3\2\2\2\u008b\u008c") 65 | buf.write("\7r\2\2\u008c\u008d\7g\2\2\u008d\u008e\7p\2\2\u008e\u008f") 66 | buf.write("\7f\2\2\u008f\u0090\7q\2\2\u0090\u0091\7y\2\2\u0091\u0092") 67 | buf.write("\7p\2\2\u0092\"\3\2\2\2\u0093\u0094\7r\2\2\u0094\u0095") 68 | buf.write("\7c\2\2\u0095\u0096\7w\2\2\u0096\u0097\7u\2\2\u0097\u0098") 69 | buf.write("\7g\2\2\u0098$\3\2\2\2\u0099\u009a\7-\2\2\u009a&\3\2\2") 70 | buf.write("\2\u009b\u009c\7/\2\2\u009c(\3\2\2\2\u009d\u009e\7,\2") 71 | buf.write("\2\u009e*\3\2\2\2\u009f\u00a0\7\61\2\2\u00a0,\3\2\2\2") 72 | buf.write("\u00a1\u00a2\7r\2\2\u00a2\u00a3\7g\2\2\u00a3\u00a4\7p") 73 | buf.write("\2\2\u00a4\u00a5\7f\2\2\u00a5\u00a6\7q\2\2\u00a6\u00a7") 74 | buf.write("\7y\2\2\u00a7\u00a8\7p\2\2\u00a8\u00a9\7A\2\2\u00a9.\3") 75 | buf.write("\2\2\2\u00aa\u00ab\7>\2\2\u00ab\60\3\2\2\2\u00ac\u00ad") 76 | buf.write("\7@\2\2\u00ad\62\3\2\2\2\u00ae\u00af\7?\2\2\u00af\u00b0") 77 | buf.write("\7?\2\2\u00b0\64\3\2\2\2\u00b1\u00b2\7#\2\2\u00b2\u00b3") 78 | buf.write("\7?\2\2\u00b3\66\3\2\2\2\u00b4\u00b5\7>\2\2\u00b5\u00b6") 79 | buf.write("\7?\2\2\u00b68\3\2\2\2\u00b7\u00b8\7@\2\2\u00b8\u00b9") 80 | buf.write("\7?\2\2\u00b9:\3\2\2\2\u00ba\u00bb\7(\2\2\u00bb\u00bc") 81 | buf.write("\7(\2\2\u00bc<\3\2\2\2\u00bd\u00be\7~\2\2\u00be\u00bf") 82 | buf.write("\7~\2\2\u00bf>\3\2\2\2\u00c0\u00c1\7#\2\2\u00c1@\3\2\2") 83 | buf.write("\2\u00c2\u00c4\t\2\2\2\u00c3\u00c2\3\2\2\2\u00c4\u00c5") 84 | buf.write("\3\2\2\2\u00c5\u00c3\3\2\2\2\u00c5\u00c6\3\2\2\2\u00c6") 85 | buf.write("B\3\2\2\2\u00c7\u00c8\7<\2\2\u00c8\u00cc\t\3\2\2\u00c9") 86 | buf.write("\u00cb\t\4\2\2\u00ca\u00c9\3\2\2\2\u00cb\u00ce\3\2\2\2") 87 | buf.write("\u00cc\u00ca\3\2\2\2\u00cc\u00cd\3\2\2\2\u00cdD\3\2\2") 88 | buf.write("\2\u00ce\u00cc\3\2\2\2\u00cf\u00d1\t\5\2\2\u00d0\u00cf") 89 | buf.write("\3\2\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d0\3\2\2\2\u00d2") 90 | buf.write("\u00d3\3\2\2\2\u00d3F\3\2\2\2\u00d4\u00d6\t\6\2\2\u00d5") 91 | buf.write("\u00d4\3\2\2\2\u00d6\u00d7\3\2\2\2\u00d7\u00d5\3\2\2\2") 92 | buf.write("\u00d7\u00d8\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00da\b") 93 | buf.write("$\2\2\u00daH\3\2\2\2\7\2\u00c5\u00cc\u00d2\u00d7\3\b\2") 94 | buf.write("\2") 95 | return buf.getvalue() 96 | 97 | 98 | class tlangLexer(Lexer): 99 | 100 | atn = ATNDeserializer().deserialize(serializedATN()) 101 | 102 | decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] 103 | 104 | T__0 = 1 105 | T__1 = 2 106 | T__2 = 3 107 | T__3 = 4 108 | T__4 = 5 109 | T__5 = 6 110 | T__6 = 7 111 | T__7 = 8 112 | T__8 = 9 113 | T__9 = 10 114 | T__10 = 11 115 | T__11 = 12 116 | T__12 = 13 117 | T__13 = 14 118 | T__14 = 15 119 | T__15 = 16 120 | T__16 = 17 121 | PLUS = 18 122 | MINUS = 19 123 | MUL = 20 124 | DIV = 21 125 | PENCOND = 22 126 | LT = 23 127 | GT = 24 128 | EQ = 25 129 | NEQ = 26 130 | LTE = 27 131 | GTE = 28 132 | AND = 29 133 | OR = 30 134 | NOT = 31 135 | NUM = 32 136 | VAR = 33 137 | NAME = 34 138 | Whitespace = 35 139 | 140 | channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] 141 | 142 | modeNames = [ "DEFAULT_MODE" ] 143 | 144 | literalNames = [ "", 145 | "'if'", "'['", "']'", "'else'", "'repeat'", "'goto'", "'('", 146 | "','", "')'", "'='", "'forward'", "'backward'", "'left'", "'right'", 147 | "'penup'", "'pendown'", "'pause'", "'+'", "'-'", "'*'", "'/'", 148 | "'pendown?'", "'<'", "'>'", "'=='", "'!='", "'<='", "'>='", 149 | "'&&'", "'||'", "'!'" ] 150 | 151 | symbolicNames = [ "", 152 | "PLUS", "MINUS", "MUL", "DIV", "PENCOND", "LT", "GT", "EQ", 153 | "NEQ", "LTE", "GTE", "AND", "OR", "NOT", "NUM", "VAR", "NAME", 154 | "Whitespace" ] 155 | 156 | ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", 157 | "T__7", "T__8", "T__9", "T__10", "T__11", "T__12", "T__13", 158 | "T__14", "T__15", "T__16", "PLUS", "MINUS", "MUL", "DIV", 159 | "PENCOND", "LT", "GT", "EQ", "NEQ", "LTE", "GTE", "AND", 160 | "OR", "NOT", "NUM", "VAR", "NAME", "Whitespace" ] 161 | 162 | grammarFileName = "tlang.g4" 163 | 164 | def __init__(self, input=None, output:TextIO = sys.stdout): 165 | super().__init__(input, output) 166 | self.checkVersion("4.7.2") 167 | self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) 168 | self._actions = None 169 | self._predicates = None 170 | 171 | 172 | -------------------------------------------------------------------------------- /ChironCore/chiron.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | Release = "Chiron v1.0.4" 3 | 4 | import ast 5 | import sys 6 | from ChironAST.builder import astGenPass 7 | import abstractInterpretation as AI 8 | import dataFlowAnalysis as DFA 9 | from sbfl import testsuiteGenerator 10 | 11 | sys.path.insert(0, "../Submission/") 12 | sys.path.insert(0, "ChironAST/") 13 | sys.path.insert(0, "cfg/") 14 | 15 | import pickle 16 | import time 17 | import turtle 18 | import argparse 19 | from interpreter import * 20 | from irhandler import * 21 | from fuzzer import * 22 | import sExecution as se 23 | import cfg.cfgBuilder as cfgB 24 | import submissionDFA as DFASub 25 | import submissionAI as AISub 26 | from sbflSubmission import computeRanks 27 | import csv 28 | 29 | 30 | def cleanup(): 31 | pass 32 | 33 | 34 | def stopTurtle(): 35 | turtle.bye() 36 | 37 | 38 | if __name__ == "__main__": 39 | print(Release) 40 | print( 41 | """ 42 | ░█████╗░██╗░░██╗██╗██████╗░░█████╗░███╗░░██╗ 43 | ██╔══██╗██║░░██║██║██╔══██╗██╔══██╗████╗░██║ 44 | ██║░░╚═╝███████║██║██████╔╝██║░░██║██╔██╗██║ 45 | ██║░░██╗██╔══██║██║██╔══██╗██║░░██║██║╚████║ 46 | ╚█████╔╝██║░░██║██║██║░░██║╚█████╔╝██║░╚███║ 47 | ░╚════╝░╚═╝░░╚═╝╚═╝╚═╝░░╚═╝░╚════╝░╚═╝░░╚══╝ 48 | """ 49 | ) 50 | 51 | # process the command-line arguments 52 | cmdparser = argparse.ArgumentParser( 53 | description="Program Analysis Framework for ChironLang Programs." 54 | ) 55 | 56 | # add arguments for parsing command-line arguments 57 | cmdparser.add_argument( 58 | "-p", 59 | "--ir", 60 | action="store_true", 61 | help="pretty printing the IR of a Chiron program to stdout (terminal)", 62 | ) 63 | cmdparser.add_argument( 64 | "-r", 65 | "--run", 66 | action="store_true", 67 | help="execute Chiron program, the figure/shapes the turle draws is shown in a UI.", 68 | ) 69 | 70 | cmdparser.add_argument( 71 | "-gr", 72 | "--fuzzer_gen_rand", 73 | action="store_true", 74 | help="Generate random input seeds for the fuzzer before fuzzing starts.", 75 | ) 76 | 77 | cmdparser.add_argument( 78 | "-b", "--bin", action="store_true", help="load binary IR of a Chiron program" 79 | ) 80 | 81 | cmdparser.add_argument( 82 | "-k", "--hooks", action="store_true", help="Run hooks for Kachua." 83 | ) 84 | 85 | cmdparser.add_argument( 86 | "-z", 87 | "--fuzz", 88 | action="store_true", 89 | help="Run fuzzer on a Chiron program (seed values with '-d' or '--params' flag needed.)", 90 | ) 91 | cmdparser.add_argument( 92 | "-t", 93 | "--timeout", 94 | default=10, 95 | type=float, 96 | help="Timeout Parameter for Analysis (in secs). This is the total timeout.", 97 | ) 98 | cmdparser.add_argument("progfl") 99 | 100 | # passing variable values via command line. E.g. 101 | # ./chiron.py -r --params '{":x" : 10, ":z" : 20, ":w" : 10, ":k" : 2}' 102 | cmdparser.add_argument( 103 | "-d", 104 | "--params", 105 | default=dict(), 106 | type=ast.literal_eval, 107 | help="pass variable values to Chiron program in python dictionary format", 108 | ) 109 | cmdparser.add_argument( 110 | "-c", 111 | "--constparams", 112 | default=dict(), 113 | type=ast.literal_eval, 114 | help="pass variable(for which you have to find values using circuit equivalence) values to Chiron program in python dictionary format", 115 | ) 116 | cmdparser.add_argument( 117 | "-se", 118 | "--symbolicExecution", 119 | action="store_true", 120 | help="Run Symbolic Execution on a Chiron program (seed values with '-d' or '--params' flag needed) to generate test cases along all possible paths.", 121 | ) 122 | # TODO: add additional arguments for parsing command-line arguments 123 | 124 | cmdparser.add_argument( 125 | "-ai", 126 | "--abstractInterpretation", 127 | action="store_true", 128 | help="Run abstract interpretation on a Chiron Program.", 129 | ) 130 | cmdparser.add_argument( 131 | "-dfa", 132 | "--dataFlowAnalysis", 133 | action="store_true", 134 | help="Run data flow analysis using worklist algorithm on a Chiron Program.", 135 | ) 136 | 137 | cmdparser.add_argument( 138 | "-sbfl", 139 | "--SBFL", 140 | action="store_true", 141 | help="Run Spectrum-basedFault localizer on Chiron program", 142 | ) 143 | cmdparser.add_argument("-bg", "--buggy", help="buggy Chiron program path", type=str) 144 | cmdparser.add_argument( 145 | "-vars", 146 | "--inputVarsList", 147 | help="A list of input variables of given Chiron program", 148 | type=str, 149 | ) 150 | cmdparser.add_argument( 151 | "-nt", "--ntests", help="number of tests to generate", default=10, type=int 152 | ) 153 | cmdparser.add_argument( 154 | "-pop", 155 | "--popsize", 156 | help="population size for Genetic Algorithm.", 157 | default=100, 158 | type=int, 159 | ) 160 | cmdparser.add_argument( 161 | "-cp", "--cxpb", help="cross-over probability", default=1.0, type=float 162 | ) 163 | cmdparser.add_argument( 164 | "-mp", "--mutpb", help="mutation probability", default=1.0, type=float 165 | ) 166 | cmdparser.add_argument( 167 | "-cfg_gen", 168 | "--control_flow", 169 | help="Generate the CFG of the given turtle program", 170 | action="store_true", 171 | ) 172 | cmdparser.add_argument( 173 | "-cfg_dump", 174 | "--dump_cfg", 175 | help="Generate the CFG of the given turtle program", 176 | action="store_true", 177 | ) 178 | cmdparser.add_argument( 179 | "-dump", 180 | "--dump_ir", 181 | help="Dump the IR to a .kw (pickle file)", 182 | action="store_true", 183 | ) 184 | cmdparser.add_argument( 185 | "-ng", 186 | "--ngen", 187 | help="number of times Genetic Algorithm iterates", 188 | default=100, 189 | type=int, 190 | ) 191 | cmdparser.add_argument( 192 | "-vb", 193 | "--verbose", 194 | help="To display computation to Console", 195 | default=True, 196 | type=bool, 197 | ) 198 | 199 | args = cmdparser.parse_args() 200 | ir = "" 201 | 202 | if not (type(args.params) is dict): 203 | raise ValueError("Wrong type for command line arguement '-d' or '--params'.") 204 | 205 | # Instantiate the irHandler 206 | # this object is passed around everywhere. 207 | irHandler = IRHandler(ir) 208 | 209 | # generate IR 210 | if args.bin: 211 | ir = irHandler.loadIR(args.progfl) 212 | else: 213 | parseTree = getParseTree(args.progfl) 214 | astgen = astGenPass() 215 | ir = astgen.visitStart(parseTree) 216 | 217 | # Set the IR of the program. 218 | irHandler.setIR(ir) 219 | 220 | # generate control_flow_graph from IR statements. 221 | if args.control_flow: 222 | cfg = cfgB.buildCFG(ir, "control_flow_graph", True) 223 | irHandler.setCFG(cfg) 224 | else: 225 | irHandler.setCFG(None) 226 | 227 | if args.dump_cfg: 228 | cfgB.dumpCFG(cfg, "control_flow_graph") 229 | # set the cfg of the program. 230 | 231 | if args.ir: 232 | irHandler.pretty_print(irHandler.ir) 233 | 234 | if args.abstractInterpretation: 235 | AISub.analyzeUsingAI(irHandler) 236 | print("== Abstract Interpretation ==") 237 | 238 | if args.dataFlowAnalysis: 239 | irOpt = DFASub.optimizeUsingDFA(irHandler) 240 | print("== Optimized IR ==") 241 | irHandler.pretty_print(irHandler.ir) 242 | 243 | if args.dump_ir: 244 | irHandler.pretty_print(irHandler.ir) 245 | irHandler.dumpIR("optimized.kw", irHandler.ir) 246 | 247 | if args.symbolicExecution: 248 | print("symbolicExecution") 249 | if not args.params: 250 | raise RuntimeError( 251 | "Symbolic Execution needs initial seed values. Specify using '-d' or '--params' flag." 252 | ) 253 | """ 254 | How to run symbolicExecution? 255 | # ./chiron.py -t 100 --symbolicExecution example/example2.tl -d '{":dir": 10, ":move": -90}' 256 | """ 257 | se.symbolicExecutionMain( 258 | irHandler, args.params, args.constparams, timeLimit=args.timeout 259 | ) 260 | 261 | if args.fuzz: 262 | if not args.params: 263 | raise RuntimeError( 264 | "Fuzzing needs initial seed values. Specify using '-d' or '--params' flag." 265 | ) 266 | """ 267 | How to run fuzzer? 268 | # ./chiron.py -t 100 --fuzz example/example1.tl -d '{":x": 5, ":y": 100}' 269 | # ./chiron.py -t 100 --fuzz example/example2.tl -d '{":dir": 3, ":move": 5}' 270 | """ 271 | fuzzer = Fuzzer(irHandler, args) 272 | cov, corpus = fuzzer.fuzz( 273 | timeLimit=args.timeout, generateRandom=args.fuzzer_gen_rand 274 | ) 275 | print(f"Coverage : {cov.total_metric},\nCorpus:") 276 | for index, x in enumerate(corpus): 277 | print(f"\tInput {index} : {x.data}") 278 | 279 | if args.run: 280 | # for stmt,pc in ir: 281 | # print(str(stmt.__class__.__bases__[0].__name__),pc) 282 | 283 | inptr = ConcreteInterpreter(irHandler, args) 284 | terminated = False 285 | inptr.initProgramContext(args.params) 286 | while True: 287 | terminated = inptr.interpret() 288 | if terminated: 289 | break 290 | print("Program Ended.") 291 | print() 292 | print("Press ESCAPE to exit") 293 | turtle.listen() 294 | turtle.onkeypress(stopTurtle, "Escape") 295 | turtle.mainloop() 296 | 297 | if args.SBFL: 298 | if not args.buggy: 299 | raise RuntimeError( 300 | "test-suite generator needs buggy program also. Specify using '--buggy' flag." 301 | ) 302 | if not args.inputVarsList: 303 | raise RuntimeError( 304 | "please specify input variable list. Specify using '--inputVarsList' or '-vars' flag." 305 | ) 306 | """ 307 | How to run SBFL? 308 | Consider we have : 309 | a correct program = sbfl1.tl 310 | corresponding buggy program sbfl1_buggy.tl 311 | input variables = :x, :y :z 312 | initial test-suite size = 20. 313 | Maximum time(in sec) to run a test-case = 10. 314 | Since we want to generate optimized test suite using genetic-algorithm, 315 | therefore we also need to provide: 316 | the intial population size = 100 317 | cross-over probabiliy = 1.0 318 | mutation probability = 1.0 319 | number of times GA to iterate = 100, therefore 320 | command : ./chiron.py --SBFL ./example/sbfl1.tl --buggy ./example/sbfl1_buggy.tl \ 321 | -vars '[":x", ":y", ":z"]' --timeout 1 --ntests 20 --popsize 100 --cxpb 1.0 --mutpb 1.0 --ngen 100 --verbose True 322 | Note : if a program doesn't take any input vars them pass argument -vars as '[]' 323 | """ 324 | 325 | print("SBFL...") 326 | # generate IR of correct program 327 | parseTree = getParseTree(args.progfl) 328 | astgen = astGenPass() 329 | ir1 = astgen.visitStart(parseTree) 330 | 331 | # generate IR of buggy program 332 | parseTree = getParseTree(args.buggy) 333 | astgen = astGenPass() 334 | ir2 = astgen.visitStart(parseTree) 335 | 336 | irhandler1 = IRHandler(ir1) 337 | irhandler2 = IRHandler(ir2) 338 | 339 | # Generate Optimized Test Suite. 340 | ( 341 | original_testsuite, 342 | original_test, 343 | optimized_testsuite, 344 | optimized_test, 345 | spectrum, 346 | ) = testsuiteGenerator( 347 | irhandler1=irhandler1, 348 | irhandler2=irhandler2, 349 | inputVars=eval(args.inputVarsList), 350 | Ntests=args.ntests, 351 | timeLimit=args.timeout, 352 | popsize=args.popsize, 353 | cxpb=args.cxpb, 354 | mutpb=args.mutpb, 355 | ngen=args.ngen, 356 | verbose=args.verbose, 357 | ) 358 | # compute ranks of components and write to file 359 | computeRanks( 360 | spectrum=spectrum, 361 | outfilename="{}_componentranks.csv".format(args.buggy.replace(".tl", "")), 362 | ) 363 | 364 | # write all output data. 365 | with open( 366 | "{}_tests-original_act-mat.csv".format(args.buggy.replace(".tl", "")), "w" 367 | ) as file: 368 | writer = csv.writer(file) 369 | writer.writerows(original_testsuite) 370 | 371 | with open( 372 | "{}_tests-original.csv".format(args.buggy.replace(".tl", "")), "w" 373 | ) as file: 374 | writer = csv.writer(file) 375 | for test in original_test: 376 | writer.writerow([test]) 377 | 378 | with open( 379 | "{}_tests-optimized_act-mat.csv".format(args.buggy.replace(".tl", "")), "w" 380 | ) as file: 381 | writer = csv.writer(file) 382 | writer.writerows(optimized_testsuite) 383 | 384 | with open( 385 | "{}_tests-optimized.csv".format(args.buggy.replace(".tl", "")), "w" 386 | ) as file: 387 | writer = csv.writer(file) 388 | for test in optimized_test: 389 | writer.writerow([test]) 390 | 391 | with open("{}_spectrum.csv".format(args.buggy.replace(".tl", "")), "w") as file: 392 | writer = csv.writer(file) 393 | writer.writerows(spectrum) 394 | print("DONE..") 395 | -------------------------------------------------------------------------------- /ChironCore/sbfl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Module to generate a test-suite with optimized number of tests. 5 | """ 6 | import sys 7 | 8 | sys.path.insert(0, "../Submission/") 9 | from sbflSubmission import fitnessScore 10 | import copy 11 | import csv 12 | import random 13 | 14 | # import map 15 | import numpy as np 16 | import time 17 | from interpreter import * 18 | import argparse 19 | import math 20 | 21 | 22 | class Executor: 23 | # Execute the program using the input test 24 | # and find which components are executed by test 25 | # and the final turtle location. 26 | def __init__(self): 27 | pass 28 | 29 | def execute(self, ir, inputList={}, end=0): 30 | """ 31 | returns coverage and turtle location at the end of program. 32 | """ 33 | coverage = [] 34 | inptr = ConcreteInterpreter(ir, None) 35 | inptr.pc = 0 36 | terminated = False 37 | inptr.initProgramContext(inputList) 38 | # The maximum time given to execute a test case. 39 | while time.time() <= end: 40 | coverage.append(inptr.pc) 41 | terminated = inptr.interpret() 42 | if terminated: 43 | break 44 | if time.time() >= end: 45 | print(f"[SBFL] Program took too long to execute. Terminated\n") 46 | else: 47 | print("[SBFL] Program Ended.\n") 48 | 49 | # final turtle location. 50 | turtle_pos = inptr.trtl.pos() 51 | 52 | return list(set(coverage)), turtle_pos 53 | 54 | 55 | # Genetic Algorithm takes object of type Individual 56 | class Individual: 57 | def __init__(self, individual): 58 | self.individual = individual # activity matrix 59 | self.fitness = None # fitness-score of activity matrix 60 | self.fitness_valid = False # flag varible used by Genetic Algorithm 61 | 62 | 63 | # GenticAlgo class is implementation of Genetic Algorithm. 64 | class GeneticAlgo: 65 | def __init__(self, spectrum, popsize, cxpb, mutpb, ngen, verbose): 66 | """ 67 | Parameters 68 | ---------- 69 | spectrum : list 70 | takes a test-suite of a program generated by SBFL class. 71 | popsize : int 72 | size of the population. 73 | cxpb : float 74 | crossover probability. 75 | mutpb : float 76 | mutation probability. 77 | ngen : int 78 | number of times genetic algorithm will iterate. 79 | verbose : boolean 80 | whther to show log of GA to console or not. 81 | """ 82 | self.program_spectrum = spectrum 83 | self.cxpb = cxpb 84 | self.mutpb = mutpb 85 | self.ngen = ngen 86 | self.popsize = popsize 87 | self.population = None 88 | self.verbose = verbose 89 | self.ntests = len(spectrum) 90 | 91 | def genPopulation(self): 92 | """ 93 | This function generate n number of random individual/spectrums 94 | using actual program's spectrum, here n = self.popsize 95 | """ 96 | self.population = [] 97 | for _ in range(self.popsize): 98 | newspectrum = copy.deepcopy(self.program_spectrum) 99 | # Generate random size test suites 100 | random.shuffle(newspectrum) 101 | Toremove = random.randint(1, len(newspectrum) - 1) 102 | for __ in range(Toremove): 103 | newspectrum.pop(random.randint(0, len(newspectrum) - 1)) 104 | self.population.append(Individual(newspectrum)) 105 | 106 | def selBest(self, population, k): 107 | """ 108 | This function selects best k individuals from population. 109 | if |population| > k, then best k individuals are returned in 110 | sorted order 111 | ---------- 112 | population : list of Individuals 113 | list of individual from where best-k individuals will be selected. 114 | k : int 115 | number of best individuals to return. 116 | Returns 117 | ------- 118 | list 119 | """ 120 | # temp contains : fitnes value, test case size, index of individual in population 121 | temp = [] 122 | for i, ind in enumerate(population): 123 | temp.append([ind.fitness, len(ind.individual), i]) 124 | temp = sorted(temp, reverse=False) #####ToDo : Fix it to generic way 125 | 126 | if len(temp) >= k: 127 | return [population[i[2]] for i in temp[:k]] 128 | else: 129 | return [population[i[2]] for i in temp] 130 | 131 | def cxAndmut(self, P1, P2): 132 | """ 133 | This function performs crossover and mutation according to self.cxpb 134 | and self.mutpb values. then returns new offsprings. 135 | ---------- 136 | P1 : Individual 137 | first Individual 138 | P2 : Individual 139 | second individual 140 | Returns 141 | ------- 142 | ind1 : Individual 143 | first offspring. 144 | ind2 : Individual 145 | second offspring. 146 | """ 147 | ind1 = copy.deepcopy(P1) 148 | ind2 = copy.deepcopy(P2) 149 | if random.random() < self.cxpb: 150 | Toshuffle = random.randint( 151 | 1, min(len(ind1.individual), len(ind2.individual)) 152 | ) 153 | for _ in range(Toshuffle): 154 | index1 = random.randint(0, len(ind1.individual) - 1) 155 | index2 = random.randint(0, len(ind2.individual) - 1) 156 | ind1.individual[index1], ind2.individual[index2] = ( 157 | ind2.individual[index2], 158 | ind1.individual[index1], 159 | ) 160 | if random.random() < self.mutpb: 161 | if random.random() < 0.5: 162 | # add randomly few test cases 163 | for ind in [ind1, ind2]: 164 | Toadd = random.randint(0, self.ntests - 1) 165 | for _ in range(Toadd): 166 | ind.individual.append(random.choice(self.program_spectrum)) 167 | else: 168 | # remove test cases randomly 169 | for ind in [ind1, ind2]: 170 | Toremove = random.randint(0, len(ind.individual) - 1) 171 | for _ in range(Toremove): 172 | ind.individual.pop(random.randint(0, len(ind.individual) - 1)) 173 | # remove fitness to None and flag to false i.e it is a new individual 174 | ind1.fitness = None 175 | ind1.fitness_valid = False 176 | ind2.fitness = None 177 | ind2.fitness_valid = False 178 | return ind1, ind2 179 | 180 | def removeDuplicates(self, population): 181 | """ 182 | This is a utility function to remove duplicate Individuals from a list 183 | of population. Here duplicate means spectrum1 == spectrum2 184 | Note : Dictonary datastructure is used to optimize the search time. 185 | Since for list its O(n) where n = |population| and for dictonary its 186 | O(1) 187 | Parameters 188 | ---------- 189 | population : list of Individuals 190 | Returns 191 | ------- 192 | list of Individuals with no duplicates. 193 | """ 194 | temp = self.selBest(population, len(population)) 195 | D = {} 196 | for i in temp: 197 | act_mat = np.array(i.individual) 198 | act_mat = act_mat[:, : act_mat.shape[1] - 1] 199 | arr_bytes = act_mat.tobytes() 200 | if arr_bytes not in D: 201 | D[arr_bytes] = i 202 | population = list(D.values()) 203 | return self.selBest(population, len(population)) 204 | 205 | def execute(self): 206 | """ 207 | This function will start executing GA. 208 | The best individuals can be accessed by self.population 209 | 210 | Returns 211 | ------- 212 | None. 213 | """ 214 | # geneate population. 215 | self.genPopulation() 216 | 217 | # compute fitness of Individuals in population 218 | fitnesses = map(fitnessScore, self.population) 219 | for ind, fit in zip(self.population, fitnesses): 220 | ind.fitness = fit 221 | ind.fitness_valid = True 222 | 223 | # sort population according to fitness score 224 | self.population = self.selBest(self.population, len(self.population)) 225 | 226 | # Iterate ngen times. 227 | for itr in range(1, self.ngen + 1): 228 | offsprings = [] 229 | for i in range(0, len(self.population) - 1, 2): 230 | P1, P2 = self.population[i], self.population[i + 1] 231 | O1, O2 = self.cxAndmut(P1, P2) 232 | 233 | O1.fitness = fitnessScore(O1) 234 | O1.fitness_valid = True 235 | O2.fitness = fitnessScore(O2) 236 | O2.fitness_valid = True 237 | 238 | # compute minimum fitness-score of parent and offspring 239 | fp, fo = min(P1.fitness, P2.fitness), min(O1.fitness, O2.fitness) 240 | 241 | # compute test total test cases in parents and offsprings 242 | lp, lo = len(P1.individual) + len(P2.individual), len( 243 | O1.individual 244 | ) + len(O2.individual) 245 | 246 | # best individual of current population 247 | Tb = self.population[0] 248 | 249 | if fo < fp or ((fo == fp) and (lo <= lp)): 250 | for O in [O1, O2]: 251 | if len(O.individual) <= 2 * len(Tb.individual): 252 | offsprings.append(O) 253 | 254 | # add offsprings into population. 255 | self.population += offsprings 256 | 257 | # remove duplicate Individuals 258 | self.population = self.removeDuplicates(self.population) 259 | 260 | # Sort population according to the fitness-score. 261 | self.population = self.selBest(self.population, self.popsize) 262 | 263 | if self.verbose: 264 | print( 265 | "Iteration : {}, Best fit-score : {}, |pop|: {}, |Test-Suite| :{}".format( 266 | itr, 267 | self.population[0].fitness, 268 | len(self.population), 269 | len(self.population[0].individual), 270 | ) 271 | ) 272 | 273 | 274 | class FaultOrcale: 275 | def __init__(self, ir1, ir2, reducedTests): 276 | self.ir1 = ir1 277 | self.ir2 = ir2 278 | self.reducedTests = reducedTests 279 | 280 | 281 | class SBFLAnalysis(ConcreteInterpreter): 282 | def __init__(self, irHandler, timeLimit=10): 283 | super().__init__(irHandler) 284 | self.ir = irHandler.ir 285 | self.irhandler = irHandler 286 | self.allinputList = [] 287 | self.timeLimit = timeLimit 288 | self.executor = Executor() 289 | 290 | def generateActivityMatrix(self, tests): 291 | self.allinputList = tests 292 | 293 | total_tests = len(tests) 294 | 295 | # initialize ir interpreter. 296 | executer = Executor() 297 | 298 | # total number of compoents in ir, each line is considered as a component. 299 | components = len(self.irhandler.ir) 300 | 301 | # Note : last column contains index of test, used for fault oracle. 302 | activity_mat = np.zeros((total_tests, components + 1), dtype="int") 303 | 304 | for index in range(total_tests): 305 | inputList = self.allinputList[index] 306 | endLimit = time.time() + self.timeLimit 307 | 308 | # get which components are executed. 309 | coverage, _ = executer.execute(self.irhandler, inputList=inputList, end=endLimit) 310 | 311 | # set executed compoent to 1 312 | activity_mat[index, coverage] = 1 313 | 314 | # index of test is also store in the activity matrix, 315 | # later it will help to fault oracle to find whether test fails or 316 | # passes. 317 | activity_mat[index, -1] = index 318 | 319 | return activity_mat.tolist() 320 | 321 | def generateSpectrum(self, orcl, timeLimit=360): 322 | # run correct and buggy program to get error vector [Fault Oracle] 323 | spectrum = np.zeros((len(orcl.reducedTests), len(orcl.ir2.ir) + 1), dtype="int") 324 | executer = Executor() 325 | 326 | for i, test in enumerate(orcl.reducedTests): 327 | _, ir1_trltl_pos = executer.execute( 328 | ir=orcl.ir1, end=(time.time() + timeLimit), inputList=test 329 | ) 330 | cov, ir2_trltl_pos = executer.execute( 331 | ir=orcl.ir2, end=(time.time() + timeLimit), inputList=test 332 | ) 333 | spectrum[i, cov] = 1 334 | if ir1_trltl_pos == ir2_trltl_pos: 335 | spectrum[i, -1] = 0 # test-case passes. 336 | else: 337 | spectrum[i, -1] = 1 # test-case fails. 338 | 339 | return spectrum.tolist() 340 | 341 | def mutateinput(self, inp): 342 | choice = random.random() 343 | if choice < 0.3: 344 | return -inp 345 | else: 346 | if inp == 0: 347 | bit_len = 1 348 | else: 349 | bit_len = math.floor(math.log(abs(inp), 2) + 1) 350 | return inp ^ (random.getrandbits(bit_len + 1)) 351 | 352 | def generateTests(self, inputVars, total_tests): 353 | allinputList = [] 354 | if inputVars == []: 355 | allinputList = [{} for i in range(total_tests)] 356 | else: 357 | # initially select random numbers as initial seed 358 | inputDict = {} 359 | for var in inputVars: 360 | inputDict[var] = random.randint(-100, 100) 361 | allinputList.append(inputDict) 362 | del inputDict 363 | for i in range(total_tests - 1): 364 | inputDict = {} 365 | for var in inputVars: 366 | inputDict[var] = self.mutateinput(allinputList[i][var]) 367 | allinputList.append(inputDict) 368 | # print("Generated Random Inputs ",allinputList) 369 | return allinputList 370 | 371 | 372 | def testsuiteGenerator( 373 | irhandler1, 374 | irhandler2, 375 | inputVars=[], 376 | Ntests=10, 377 | timeLimit=10, 378 | popsize=50, 379 | cxpb=0.5, 380 | mutpb=0.5, 381 | ngen=50, 382 | verbose=True, 383 | ): 384 | # execute correct program to get activity matrix. it will be used by 385 | # genetic algorithm to optimize the test-suite size 386 | sbfl_object = SBFLAnalysis(irHandler=irhandler1, timeLimit=timeLimit) 387 | 388 | # generate random tests 389 | original_tests = sbfl_object.generateTests(inputVars=inputVars, total_tests=Ntests) 390 | 391 | oracle = FaultOrcale(irhandler1, irhandler2, original_tests) 392 | 393 | ActivityMatrix = sbfl_object.generateActivityMatrix(original_tests) 394 | original_test_suites = np.array(ActivityMatrix, dtype="int") 395 | original_test_suites = original_test_suites[ 396 | :, : original_test_suites.shape[1] - 1 397 | ].tolist() 398 | 399 | # optimize test-suite and get the best indivudual return by GA. 400 | genOpt = GeneticAlgo( 401 | spectrum=ActivityMatrix, 402 | popsize=popsize, 403 | cxpb=cxpb, 404 | mutpb=mutpb, 405 | ngen=ngen, 406 | verbose=verbose, 407 | ) 408 | genOpt.execute() 409 | pop = genOpt.population 410 | best_individual = pop[0].individual 411 | 412 | # get tests indexs 413 | reduced_tests = [] 414 | for tests in best_individual: 415 | reduced_tests.append(original_tests[tests[-1]]) 416 | 417 | reduced_act_mat = np.array(best_individual, dtype="int") 418 | reduced_act_mat = reduced_act_mat[:, : reduced_act_mat.shape[1] - 1] 419 | 420 | orcl = FaultOrcale(irhandler1, irhandler2, reduced_tests) 421 | spectrum = sbfl_object.generateSpectrum(orcl) 422 | 423 | return ( 424 | original_test_suites, 425 | original_tests, 426 | reduced_act_mat, 427 | reduced_tests, 428 | spectrum, 429 | ) 430 | --------------------------------------------------------------------------------