xpcom/analysis/flow.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 require({ version: '1.8' });
michael@0 6 require({ after_gcc_pass: 'cfg' });
michael@0 7
michael@0 8 include('treehydra.js');
michael@0 9
michael@0 10 include('util.js');
michael@0 11 include('gcc_util.js');
michael@0 12 include('gcc_print.js');
michael@0 13 include('unstable/adts.js');
michael@0 14 include('unstable/analysis.js');
michael@0 15 include('unstable/esp.js');
michael@0 16
michael@0 17 /* This implements the control flows-through analysis in bug 432917 */
michael@0 18 var Zero_NonZero = {}
michael@0 19 include('unstable/zero_nonzero.js', Zero_NonZero);
michael@0 20
michael@0 21 MapFactory.use_injective = true;
michael@0 22
michael@0 23 // Print a trace for each function analyzed
michael@0 24 let TRACE_FUNCTIONS = 0;
michael@0 25 // Trace operation of the ESP analysis, use 2 or 3 for more detail
michael@0 26 let TRACE_ESP = 0;
michael@0 27 // Print time-taken stats
michael@0 28 let TRACE_PERF = 0;
michael@0 29
michael@0 30 function process_tree(fndecl) {
michael@0 31 // At this point we have a function we want to analyze
michael@0 32 if (TRACE_FUNCTIONS) {
michael@0 33 print('* function ' + decl_name(fndecl));
michael@0 34 print(' ' + loc_string(location_of(fndecl)));
michael@0 35 }
michael@0 36 if (TRACE_PERF) timer_start(fstring);
michael@0 37
michael@0 38 let cfg = function_decl_cfg(fndecl);
michael@0 39
michael@0 40 try {
michael@0 41 let trace = TRACE_ESP;
michael@0 42 let a = new FlowCheck(cfg, trace);
michael@0 43 a.run();
michael@0 44 } catch (e if e == "skip") {
michael@0 45 return
michael@0 46 }
michael@0 47 print("checked " + decl_name(fndecl))
michael@0 48 if (cfg.x_exit_block_ptr.stateIn.substates)
michael@0 49 for each (let substate in cfg.x_exit_block_ptr.stateIn.substates.getValues()) {
michael@0 50 for each (let v in substate.getVariables()) {
michael@0 51 let var_state= substate.get (v)
michael@0 52 let blame = substate.getBlame(v)
michael@0 53 if (var_state != ESP.TOP && typeof var_state == 'string')
michael@0 54 error(decl_name(fndecl) + ": Control did not flow through " +var_state, location_of(blame))
michael@0 55 }
michael@0 56 }
michael@0 57
michael@0 58 if (TRACE_PERF) timer_stop(fstring);
michael@0 59 }
michael@0 60
michael@0 61 let track_return_loc = 0;
michael@0 62 const FLOW_THROUGH = "MUST_FLOW_THROUGH"
michael@0 63
michael@0 64 function FlowCheck(cfg, trace) {
michael@0 65 let found = create_decl_set(); // ones we already found
michael@0 66 for (let bb in cfg_bb_iterator(cfg)) {
michael@0 67 for (let isn in bb_isn_iterator(bb)) {
michael@0 68 switch (isn.tree_code()) {
michael@0 69 case GIMPLE_CALL: {
michael@0 70 let fn = gimple_call_fndecl(isn)
michael@0 71 if (!fn || decl_name(fn) != FLOW_THROUGH)
michael@0 72 continue;
michael@0 73 this.must_flow_fn = fn
michael@0 74 break
michael@0 75 }
michael@0 76 case GIMPLE_RETURN:
michael@0 77 let ret_expr = return_expr(isn);
michael@0 78 if (track_return_loc && ret_expr) {
michael@0 79 TREE_CHECK(ret_expr, VAR_DECL, RESULT_DECL);
michael@0 80 this.rval = ret_expr;
michael@0 81 }
michael@0 82 break;
michael@0 83 }
michael@0 84 }
michael@0 85 }
michael@0 86 if (!this.must_flow_fn)
michael@0 87 throw "skip"
michael@0 88
michael@0 89 let psvar_list = [new ESP.PropVarSpec(this.must_flow_fn, true)]
michael@0 90
michael@0 91 if (this.rval)
michael@0 92 psvar_list.push(new ESP.PropVarSpec(this.rval))
michael@0 93
michael@0 94 this.zeroNonzero = new Zero_NonZero.Zero_NonZero()
michael@0 95 ESP.Analysis.call(this, cfg, psvar_list, Zero_NonZero.meet, trace);
michael@0 96 }
michael@0 97
michael@0 98 FlowCheck.prototype = new ESP.Analysis;
michael@0 99
michael@0 100 function char_star_arg2string(tree) {
michael@0 101 return TREE_STRING_POINTER(tree.tree_check(ADDR_EXPR).operands()[0].tree_check(ARRAY_REF).operands()[0])
michael@0 102 }
michael@0 103
michael@0 104 // State transition function. Mostly, we delegate everything to
michael@0 105 // another function as either an assignment or a call.
michael@0 106 FlowCheck.prototype.flowState = function(isn, state) {
michael@0 107 switch (TREE_CODE(isn)) {
michael@0 108 case GIMPLE_CALL: {
michael@0 109 let fn = gimple_call_fndecl(isn)
michael@0 110 if (fn == this.must_flow_fn)
michael@0 111 state.assignValue(fn, char_star_arg2string(gimple_call_arg(isn, 0)), isn)
michael@0 112 break
michael@0 113 }
michael@0 114 case GIMPLE_LABEL: {
michael@0 115 let label = decl_name(gimple_op(isn, 0))
michael@0 116 for ([value, blame] in state.yieldPreconditions(this.must_flow_fn)) {
michael@0 117 if (label != value) continue
michael@0 118 // reached the goto label we wanted =D
michael@0 119 state.assignValue(this.must_flow_fn, ESP.TOP, isn)
michael@0 120 }
michael@0 121 break
michael@0 122 }
michael@0 123 case GIMPLE_RETURN:
michael@0 124 for ([value, blame] in state.yieldPreconditions(this.must_flow_fn)) {
michael@0 125 if (typeof value != 'string') continue
michael@0 126 let loc;
michael@0 127 if (this.rval)
michael@0 128 for ([value, blame] in state.yieldPreconditions(this.rval)) {
michael@0 129 loc = value
michael@0 130 break
michael@0 131 }
michael@0 132 error("return without going through label "+ value, loc);
michael@0 133 return
michael@0 134 }
michael@0 135 break
michael@0 136 case GIMPLE_ASSIGN:
michael@0 137 if (track_return_loc && gimple_op(isn, 0) == this.rval) {
michael@0 138 state.assignValue(this.rval, location_of(isn), isn)
michael@0 139 break
michael@0 140 }
michael@0 141 default:
michael@0 142 this.zeroNonzero.flowState(isn, state)
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 // State transition function to apply branch filters. This is kind
michael@0 147 // of boilerplate--we're just handling some stuff that GCC generates.
michael@0 148 FlowCheck.prototype.flowStateCond = function(isn, truth, state) {
michael@0 149 this.zeroNonzero.flowStateCond (isn, truth, state)
michael@0 150 }

mercurial