-
Notifications
You must be signed in to change notification settings - Fork 119
/
analysisCallbackTemplate.js
646 lines (610 loc) · 35.5 KB
/
analysisCallbackTemplate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
/*
* Copyright 2014 Samsung Information Systems America, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: Koushik Sen
// do not remove the following comment
// JALANGI DO NOT INSTRUMENT
/**
* @file A template for writing a Jalangi 2 analysis
* @author Koushik Sen
*
*/
(function (sandbox) {
/**
* <p>
* This file is a template for writing a custom Jalangi 2 analysis. Simply copy this file and rewrite the
* callbacks that you need to implement in your analysis. Other callbacks should be removed from the file.
*</p>
*
* <p>
* In the following methods (also called as callbacks) one can choose to not return anything.
* If all of the callbacks return nothing, we get a passive analysis where the
* concrete execution happens unmodified and callbacks can be used to observe the execution.
* One can choose to return suitable objects with specified properties in some callbacks
* to modify the behavior of the concrete execution. For example, one could set the skip
* property of the object returned from {@link MyAnalysis#putFieldPre} to true to skip the actual putField operation.
* Similarly, one could set the result field of the object returned from a {@link MyAnalysis#write} callback
* to modify the value that is actually written to a variable. The result field of the object
* returned from a {@link MyAnalysis#conditional} callback can be suitably set to change the control-flow of the
* program execution. In {@link MyAnalysis#functionExit} and {@link MyAnalysis#scriptExit},
* one can set the <tt>isBacktrack</tt> property of the returned object to true to reexecute the body of
* the function from the beginning. This in conjunction with the ability to change the
* control-flow of a program enables us to explore the different paths of a function in
* symbolic execution.
* </p>
*
* <p>
* Note that if <tt>process.exit()</tt> is called, then an execution terminates abnormally and a callback to
* {@link MyAnalysis#endExecution} will be skipped.
* </p>
*
* <p>
* An analysis can access the source map, which maps instruction identifiers to source locations,
* using the global object stored in <code>J$.smap</code>. Jalangi 2
* assigns a unique id, called <code>sid</code>, to each JavaScript
* script loaded at runtime. <code>J$.smap</code> maps each <code>sid</code> to an object, say
* <code>iids</code>, containing source map information for the script whose id is <code>sid</code>.
* <code>iids</code> has the following properties: <code>"originalCodeFileName"</code> (stores the path of the original
* script file), <code>"instrumentedCodeFileName"</code> (stores the path of the instrumented script file),
* <code>"url"</code> (is optional and stores the URL of the script if it is set during instrumentation
* using the --url option),
* <code>"evalSid"</code> (stores the sid of the script in which the eval is called in case the current script comes from
* an <code>eval</code> function call),
* <code>"evalIid"</code> (iid of the <code>eval</code> function call in case the current script comes from an
* <code>eval</code> function call), <code>"nBranches"</code> (the number of conditional statements
* in the script),
* and <code>"code"</code> (a string denoting the original script code if the code is instrumented with the
* --inlineSource option).
* <code>iids</code> also maps each <code>iid</code> (which stands for instruction id, an unique id assigned
* to each callback function inserted by Jalangi2) to an array containing
* <code>[beginLineNumber, beginColumnNumber, endLineNumber, endColumnNumber]</code>. The mapping from iids
* to arrays is only available if the code is instrumented with
* the --inlineIID option.
* </p>
* <p>
* In each callback described below, <code>iid</code> denotes the unique static instruction id of the callback in the script.
* Two callback functions inserted in two different scripts may have the same iid. In a callback function, one can access
* the current script id using <code>J$.sid</code>. One can call <code>J$.getGlobalIID(iid)</code> to get a string, called
* <code>giid</code>, that statically identifies the
* callback throughout the program. <code>J$.getGlobalIID(iid)</code> returns the string <code>J$.sid+":"+iid</code>.
* <code>J$.iidToLocation(giid)</code> returns a string
* containing the original script file path, begin and end line numbers and column numbers of the code snippet
* for which the callback with <code>giid</code> was inserted.
*
* </p>
* <p>
* A number of sample analyses can be found at {@link ../src/js/sample_analyses/}. Refer to {@link ../README.md} for instructions
* on running an analysis.
* </p>
*
*
*
* @global
* @class
*/
function MyAnalysis() {
/**
* This callback is called before a function, method, or constructor invocation.
* Note that a method invocation also triggers a {@link MyAnalysis#getFieldPre} and a
* {@link MyAnalysis#getField} callbacks.
*
* @example
* y.f(a, b, c)
*
* // the above call roughly gets instrumented as follows:
*
* var skip = false;
* var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true);
* if (aret) {
* f = aret.f;
* y = aret.y;
* args = aret.args;
* skip = aret.skip
* }
* if (!skip) {
* f.apply(y, args);
* }
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {function} f - The function object that going to be invoked
* @param {object} base - The receiver object for the function <tt>f</tt>
* @param {Array} args - The array of arguments passed to <tt>f</tt>
* @param {boolean} isConstructor - True if <tt>f</tt> is invoked as a constructor
* @param {boolean} isMethod - True if <tt>f</tt> is invoked as a method
* @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
* @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
* {@link MyAnalysis#functionEnter} when the function <tt>f</tt> is executed. The <tt>functionIid</tt> can be
* treated as the static identifier of the function <tt>f</tt>. Note that a given function code block can
* create several function objects, but each such object has a common <tt>functionIid</tt>, which is the iid
* that is passed to {@link MyAnalysis#functionEnter} when the function executes.
* @returns {{f: function, base: Object, args: Array, skip: boolean}|undefined} - If an object is returned and
* the <tt>skip</tt> property of the object is true, then the invocation operation is skipped.
* Original <tt>f</tt>, <tt>base</tt>, and <tt>args</tt> are replaced with that from the returned object if
* an object is returned.
*
*/
this.invokeFunPre = function (iid, f, base, args, isConstructor, isMethod, functionIid, functionSid) {
return {f: f, base: base, args: args, skip: false};
};
/**
* This callback is called after a function, method, or constructor invocation.
*
* @example
* x = y.f(a, b, c)
*
* // the above call roughly gets instrumented as follows:
*
* var skip = false;
* var aret = analysis.invokeFunPre(113, f, y, [a, b, c], false, true);
* if (aret) {
* f = aret.f;
* y = aret.y;
* args = aret.args;
* skip = aret.skip
* }
* if (!skip) {
* result =f.apply(y, args);
* }
* aret = analysis.invokeFun(117, f, y, args, result, false, true);
* if (aret) {
* x = aret.result
* } else {
* x = result;
* }
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {function} f - The function object that was invoked
* @param {*} base - The receiver object for the function <tt>f</tt>
* @param {Array} args - The array of arguments passed to <tt>f</tt>
* @param {*} result - The value returned by the invocation
* @param {boolean} isConstructor - True if <tt>f</tt> is invoked as a constructor
* @param {boolean} isMethod - True if <tt>f</tt> is invoked as a method
* @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
* @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
* {@link MyAnalysis#functionEnter} when the function f is executed. <tt>functionIid</tt> can be treated as the
* static identifier of the function <tt>f</tt>. Note that a given function code block can create several function
* objects, but each such object has a common <tt>functionIid</tt>, which is the iid that is passed to
* {@link MyAnalysis#functionEnter} when the function executes.
* @returns {{result: *}| undefined} - If an object is returned, the return value of the invoked function is
* replaced with the value stored in the <tt>result</tt> property of the object. This enables one to change the
* value that is returned by the actual function invocation.
*
*/
this.invokeFun = function (iid, f, base, args, result, isConstructor, isMethod, functionIid, functionSid) {
return {result: result};
};
/**
* This callback is called after the creation of a literal. A literal can be a function literal, an object literal,
* an array literal, a number, a string, a boolean, a regular expression, null, NaN, Infinity, or undefined.
*
* @example
* x = "Hello"
*
* // the above call roughly gets instrumented as follows:
*
* var result = "Hello";
* var aret = analysis.literal(201, result, false);
* if (aret) {
* result = aret.result;
* }
* x = result;
*
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} val - The literal value
* @param {boolean} hasGetterSetter - True if the literal is an object and the object defines getters and setters
* @returns {{result: *} | undefined} - If the function returns an object, then the original literal value is
* replaced with the value stored in the <tt>result</tt> property of the object.
*
*/
this.literal = function (iid, val, hasGetterSetter) {
return {result: val};
};
/**
* This callback is called when a for-in loop is used to iterate the properties of an object.
*
*@example
* for (x in y) { }
*
* // the above call roughly gets instrumented as follows:
*
* var aret = analysis.forinObject(iid, y);
* if (aret) {
* y = aret.result;
* }
* for (x in y) {}
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} val - Objects whose properties are iterated in a for-in loop.
* @returns {{result: *} | undefined} - If the function returns an object, then the original object whose
* properties are being iterated is replaced with the value stored in the <tt>result</tt> property of the
* returned object.
*
*/
this.forinObject = function (iid, val) {
return {result: val};
};
/**
* This callback is triggered at the beginning of a scope for every local variable declared in the scope, for
* every formal parameter, for every function defined using a function statement, for <tt>arguments</tt>
* variable, and for the formal parameter passed in a catch statement.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} name - Name of the variable that is declared
* @param {*} val - Initial value of the variable that is declared. Variables can be local variables, function
* parameters, catch parameters, <tt>arguments</tt>, or functions defined using function statements. Variables
* declared with <tt>var</tt> have <tt>undefined</tt> as initial values and cannot be changed by returning a
* different value from this callback. On the beginning of an execution of a function, a <tt>declare</tt>
* callback is called on the <tt>arguments</tt> variable.
* @param {boolean} isArgument - True if the variable is <tt>arguments</tt> or a formal parameter.
* @param {number} argumentIndex - Index of the argument in the function call. Indices start from 0. If the
* variable is not a formal parameter, then <tt>argumentIndex</tt> is -1.
* @param {boolean} isCatchParam - True if the variable is a parameter of a catch statement.
* @returns {{result: *} | undefined} - If the function returns an object, then the original initial value is
* replaced with the value stored in the <tt>result</tt> property of the object. This does not apply to local
* variables declared with <tt>var</tt>.
*
*/
this.declare = function (iid, name, val, isArgument, argumentIndex, isCatchParam) {
return {result: val};
};
/**
* This callback is called before a property of an object is accessed.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} base - Base object
* @param {string|*} offset - Property
* @param {boolean} isComputed - True if property is accessed using square brackets. For example,
* <tt>isComputed</tt> is <tt>true</tt> if the get field operation is <tt>o[p]</tt>, and <tt>false</tt>
* if the get field operation is <tt>o.p</tt>
* @param {boolean} isOpAssign - True if the operation is of the form <code>o.p op= e</code>
* @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. <tt>o.p()</tt>)
* @returns {{base: *, offset: *, skip: boolean} | undefined} - If an object is returned and the <tt>skip</tt>
* property of the object is true, then the get field operation is skipped. Original <tt>base</tt> and
* <tt>offset</tt> are replaced with that from the returned object if an object is returned.
*
*/
this.getFieldPre = function (iid, base, offset, isComputed, isOpAssign, isMethodCall) {
return {base: base, offset: offset, skip: false};
};
/**
* This callback is called after a property of an object is accessed.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} base - Base object
* @param {string|*} offset - Property
* @param {*} val - Value of <code>base[offset]</code>
* @param {boolean} isComputed - True if property is accessed using square brackets. For example,
* <tt>isComputed</tt> is <tt>true</tt> if the get field operation is <tt>o[p]</tt>, and <tt>false</tt>
* if the get field operation is <tt>o.p</tt>
* @param {boolean} isOpAssign - True if the operation is of the form <code>o.p op= e</code>
* @param {boolean} isMethodCall - True if the get field operation is part of a method call (e.g. <tt>o.p()</tt>)
* @returns {{result: *} | undefined} - If an object is returned, the value of the get field operation is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.getField = function (iid, base, offset, val, isComputed, isOpAssign, isMethodCall) {
return {result: val};
};
/**
* This callback is called before a property of an object is written.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} base - Base object
* @param {*} offset - Property
* @param {*} val - Value to be stored in <code>base[offset]</code>
* @param {boolean} isComputed - True if property is accessed using square brackets. For example,
* <tt>isComputed</tt> is <tt>true</tt> if the get field operation is <tt>o[p]</tt>, and <tt>false</tt>
* if the get field operation is <tt>o.p</tt>
* @param {boolean} isOpAssign - True if the operation is of the form <code>o.p op= e</code>
* @returns {{base: *, offset: *, val: *, skip: boolean} | undefined} - If an object is returned and the <tt>skip</tt>
* property is true, then the put field operation is skipped. Original <tt>base</tt>, <tt>offset</tt>, and
* <tt>val</tt> are replaced with that from the returned object if an object is returned.
*/
this.putFieldPre = function (iid, base, offset, val, isComputed, isOpAssign) {
return {base: base, offset: offset, val: val, skip: false};
};
/**
* This callback is called after a property of an object is written.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} base - Base object
* @param {*} offset - Property
* @param {*} val - Value to be stored in <code>base[offset]</code>
* @param {boolean} isComputed - True if property is accessed using square brackets. For example,
* <tt>isComputed</tt> is <tt>true</tt> if the get field operation is <tt>o[p]</tt>, and <tt>false</tt>
* if the get field operation is <tt>o.p</tt>
* @param {boolean} isOpAssign - True if the operation is of the form <code>o.p op= e</code>
* @returns {{result: *} | undefined} - If an object is returned, the result of the put field operation is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.putField = function (iid, base, offset, val, isComputed, isOpAssign) {
return {result: val};
};
/**
* This callback is called after a variable is read.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} name - Name of the variable being read
* @param {*} val - Value read from the variable
* @param {boolean} isGlobal - True if the variable is not declared using <tt>var</tt> (e.g. <tt>console</tt>)
* @param {boolean} isScriptLocal - True if the variable is declared in the global scope using <tt>var</tt>
* @returns {{result: *} | undefined} - If an object is returned, the result of the read operation is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.read = function (iid, name, val, isGlobal, isScriptLocal) {
return {result: val};
};
/**
* This callback is called before a variable is written.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} name - Name of the variable being read
* @param {*} val - Value to be written to the variable
* @param {*} lhs - Value stored in the variable before the write operation
* @param {boolean} isGlobal - True if the variable is not declared using <tt>var</tt> (e.g. <tt>console</tt>)
* @param {boolean} isScriptLocal - True if the variable is declared in the global scope using <tt>var</tt>
* @returns {{result: *} | undefined} - If an object is returned, the result of the write operation is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.write = function (iid, name, val, lhs, isGlobal, isScriptLocal) {
return {result: val};
};
/**
* This callback is called before a value is returned from a function using the <tt>return</tt> keyword.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} val - Value to be returned
* @returns {{result: *} | undefined} - If an object is returned, the value to be returned is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this._return = function (iid, val) {
return {result: val};
};
/**
* This callback is called before a value is thrown using the <tt>throw</tt> keyword.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} val - Value to be thrown
* @returns {{result: *} | undefined} - If an object is returned, the value to be thrown is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this._throw = function (iid, val) {
return {result: val};
};
/**
* This callback is called when a <tt>with</tt> statement is executed
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} val - Value used as an argument to <tt>with</tt>
* @returns {{result: *} | undefined} - If an object is returned, the value to be used in <tt>with</tt> is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this._with = function (iid, val) {
return {result: val};
};
/**
* This callback is called before the execution of a function body starts.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {function} f - The function object whose body is about to get executed
* @param {*} dis - The value of the <tt>this</tt> variable in the function body
* @param {Array} args - List of the arguments with which the function is called
* @returns {undefined} - Any return value is ignored
*/
this.functionEnter = function (iid, f, dis, args) {
};
/**
* This callback is called when the execution of a function body completes
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} returnVal - The value returned by the function
* @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the function
* execution has thrown an uncaught exception and the exception is being stored in the <tt>exception</tt>
* property of the parameter
* @returns {{returnVal: *, wrappedExceptionVal: *, isBacktrack: boolean}} If an object is returned, then the
* actual <tt>returnVal</tt> and <tt>wrappedExceptionVal.exception</tt> are replaced with that from the
* returned object. If an object is returned and the property <tt>isBacktrack</tt> is set, then the control-flow
* returns to the beginning of the function body instead of returning to the caller. The property
* <tt>isBacktrack</tt> can be set to <tt>true</tt> to repeatedly execute the function body as in MultiSE
* symbolic execution.
*/
this.functionExit = function (iid, returnVal, wrappedExceptionVal) {
return {returnVal: returnVal, wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
};
/**
* This callback is called before the execution of a JavaScript file
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} instrumentedFileName - Name of the instrumented script file
* @param {string} originalFileName - Name of the original script file
*/
this.scriptEnter = function (iid, instrumentedFileName, originalFileName) {
};
/**
* This callback is called when the execution of a JavaScript file completes
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {{exception:*} | undefined} wrappedExceptionVal - If this parameter is an object, the script
* execution has thrown an uncaught exception and the exception is being stored in the <tt>exception</tt>
* property of the parameter
* @returns {{wrappedExceptionVal: *, isBacktrack: boolean}} - If an object is returned, then the
* actual <tt>wrappedExceptionVal.exception</tt> is replaced with that from the
* returned object. If an object is returned and the property <tt>isBacktrack</tt> is set, then the control-flow
* returns to the beginning of the script body. The property
* <tt>isBacktrack</tt> can be set to <tt>true</tt> to repeatedly execute the script body as in MultiSE
* symbolic execution.
*/
this.scriptExit = function (iid, wrappedExceptionVal) {
return {wrappedExceptionVal: wrappedExceptionVal, isBacktrack: false};
};
/**
* This callback is called before a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
* <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in. No callback for <code>delete x</code>
* because this operation cannot be performed reflectively.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} op - Operation to be performed
* @param {*} left - Left operand
* @param {*} right - Right operand
* @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form
* <code>x op= e</code>
* @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant
* with a consequent in a switch statement.
* @param {boolean} isComputed - True if the operation is of the form <code>delete x[p]</code>, and false
* otherwise (even if the operation if of the form <code>delete x.p</code>)
* @returns {{op: string, left: *, right: *, skip: boolean}|undefined} - If an object is returned and the
* <tt>skip</tt> property is true, then the binary operation is skipped. Original <tt>op</tt>, <tt>left</tt>,
* and <tt>right</tt> are replaced with that from the returned object if an object is returned.
*/
this.binaryPre = function (iid, op, left, right, isOpAssign, isSwitchCaseComparison, isComputed) {
return {op: op, left: left, right: right, skip: false};
};
/**
* This callback is called after a binary operation. Binary operations include +, -, *, /, %, &, |, ^,
* <<, >>, >>>, <, >, <=, >=, ==, !=, ===, !==, instanceof, delete, in.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} op - Operation to be performed
* @param {*} left - Left operand
* @param {*} right - Right operand
* @param {*} result - The result of the binary operation
* @param {boolean} isOpAssign - True if the binary operation is part of an expression of the form
* <code>x op= e</code>
* @param {boolean} isSwitchCaseComparison - True if the binary operation is part of comparing the discriminant
* with a consequent in a switch statement.
* @param {boolean} isComputed - True if the operation is of the form <code>delete x[p]</code>, and false
* otherwise (even if the operation if of the form <code>delete x.p</code>)
* @returns {{result: *}|undefined} - If an object is returned, the result of the binary operation is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.binary = function (iid, op, left, right, result, isOpAssign, isSwitchCaseComparison, isComputed) {
return {result: result};
};
/**
* This callback is called before a unary operation. Unary operations include +, -, ~, !, typeof, void.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} op - Operation to be performed
* @param {*} left - Left operand
* @returns {{op: *, left: *, skip: boolean} | undefined} If an object is returned and the
* <tt>skip</tt> property is true, then the unary operation is skipped. Original <tt>op</tt> and <tt>left</tt>
* are replaced with that from the returned object if an object is returned.
*/
this.unaryPre = function (iid, op, left) {
return {op: op, left: left, skip: false};
};
/**
* This callback is called after a unary operation. Unary operations include +, -, ~, !, typeof, void.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {string} op - Operation to be performed
* @param {*} left - Left operand
* @param {*} result - The result of the unary operation
* @returns {{result: *}|undefined} - If an object is returned, the result of the unary operation is
* replaced with the value stored in the <tt>result</tt> property of the object.
*
*/
this.unary = function (iid, op, left, result) {
return {result: result};
};
/**
* This callback is called after a condition check before branching. Branching can happen in various statements
* including if-then-else, switch-case, while, for, ||, &&, ?:.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} result - The value of the conditional expression
* @returns {{result: *}|undefined} - If an object is returned, the result of the conditional expression is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.conditional = function (iid, result) {
return {result: result};
};
/**
* This callback is called before a string passed as an argument to eval or Function is instrumented.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} code - Code that is going to get instrumented
* @param {boolean} isDirect - true if this is a direct call to eval
* @returns {{code: *, skip: boolean}} - If an object is returned and the
* <tt>skip</tt> property is true, then the instrumentation of <tt>code</tt> is skipped.
* Original <tt>code</tt> is replaced with that from the returned object if an object is returned.
*/
this.instrumentCodePre = function (iid, code, isDirect) {
return {code: code, skip: false};
};
/**
* This callback is called after a string passed as an argument to eval or Function is instrumented.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} newCode - Instrumented code
* @param {Object} newAst - The AST of the instrumented code
* @param {boolean} isDirect - true if this is a direct call to eval
* @returns {{result: *}|undefined} - If an object is returned, the instrumented code is
* replaced with the value stored in the <tt>result</tt> property of the object.
*/
this.instrumentCode = function (iid, newCode, newAst, isDirect) {
return {result: newCode};
};
/**
* This callback is called when an expression is evaluated and its value is discarded. For example, this
* callback is called when an expression statement completes its execution.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @returns {undefined} - Any return value is ignored
*/
this.endExpression = function (iid) {
};
/**
* This callback is called when an execution terminates in node.js. In a browser environment, the callback is
* called if ChainedAnalyses.js or ChainedAnalysesNoCheck.js is used and Alt-Shift-T is pressed.
*
* @returns {undefined} - Any return value is ignored
*/
this.endExecution = function () {
};
/**
* This callback is called only when instrumented with J$.Config.ENABLE_SAMPLING = true
* This callback is called before the body of a function, method, or constructor is executed
* if returns true, instrumented function body is executed, else uninstrumented function body is executed
* @param {number} iid - Static unique instruction identifier of this callback
* @param {function} f - The function whose body is being executed
* @param {number} functionIid - The iid (i.e. the unique instruction identifier) where the function was created
* @param {number} functionSid - The sid (i.e. the unique script identifier) where the function was created
* {@link MyAnalysis#functionEnter} when the function <tt>f</tt> is executed. The <tt>functionIid</tt> can be
* treated as the static identifier of the function <tt>f</tt>. Note that a given function code block can
* create several function objects, but each such object has a common <tt>functionIid</tt>, which is the iid
* that is passed to {@link MyAnalysis#functionEnter} when the function executes.
* @returns {boolean} - If true is returned the instrumented function body is executed, otherwise the
* uninstrumented function body is executed.
*/
this.runInstrumentedFunctionBody = function (iid, f, functionIid, functionSid) {
return false;
};
/**
* onReady is useful if your analysis is running on node.js (i.e., via the direct.js or jalangi.js commands)
* and needs to complete some asynchronous initialization before the instrumented program starts. In such a
* case, once the initialization is complete, invoke the cb function to start execution of the instrumented
* program.
*
* Note that this callback is not useful in the browser, as Jalangi has no control over when the
* instrumented program runs there.
* @param cb
*/
this.onReady = function (cb) {
cb();
};
}
sandbox.analysis = new MyAnalysis();
})(J$);