Wed, 31 Dec 2014 06:09:35 +0100
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 | } |