Class: Brakeman::FindReturnValue

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/brakeman/processors/lib/find_return_value.rb

Overview

Attempts to determine the return value of a method.

Preferred usage:

Brakeman::FindReturnValue.return_value exp

Constant Summary

Constants included from Util

Util::ALL_COOKIES, Util::ALL_PARAMETERS, Util::COOKIES, Util::COOKIES_SEXP, Util::DIR_CONST, Util::LITERALS, Util::PARAMETERS, Util::PARAMS_SEXP, Util::PATH_PARAMETERS, Util::QUERY_PARAMETERS, Util::REQUEST_COOKIES, Util::REQUEST_ENV, Util::REQUEST_PARAMETERS, Util::REQUEST_PARAMS, Util::REQUEST_REQUEST_PARAMETERS, Util::SAFE_LITERAL, Util::SESSION, Util::SESSION_SEXP

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#array?, #block?, #call?, #camelize, #class_name, #constant?, #contains_class?, #cookies?, #dir_glob?, #false?, #hash?, #hash_access, #hash_insert, #hash_iterate, #integer?, #kwsplat?, #literal?, #make_call, #node_type?, #number?, #params?, #pluralize, #rails_version, #regexp?, #remove_kwsplat, #request_env?, #request_value?, #result?, #safe_literal, #safe_literal?, #safe_literal_target?, #set_env_defaults, #sexp?, #string?, #string_interp?, #symbol?, #template_path_to_name, #true?, #underscore

Constructor Details

#initializeFindReturnValue

Returns a new instance of FindReturnValue.


18
19
20
21
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 18

def initialize
  @uses_ivars = false
  @return_values = []
end

Class Method Details

.return_value(exp, env = nil) ⇒ Object

Returns a guess at the return value of a given method or other block of code.

If multiple return values are possible, returns all values in an :or Sexp.


14
15
16
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 14

def self.return_value exp, env = nil
  self.new.get_return_value exp, env
end

Instance Method Details

#find_explicit_return_values(exp) ⇒ Object

Searches expression for return statements.


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 59

def find_explicit_return_values exp
  todo = [exp]

  until todo.empty?
    current = todo.shift

    @uses_ivars = true if node_type? current, :ivar

    if node_type? current, :return
      @return_values << last_value(current.value) if current.value
    elsif sexp? current
      todo = current[1..-1].concat todo
    end
  end
end

#get_return_value(exp, env = nil) ⇒ Object

Find return value of Sexp. Takes an optional starting environment.


28
29
30
31
32
33
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 28

def get_return_value exp, env = nil
  process_method exp, env
  value = make_return_value
  value.original_line = exp.line
  value
end

#last_value(exp) ⇒ Object

Determines the “last value” of an expression.


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
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 76

def last_value exp
  case exp.node_type
  when :rlist, :block, :scope, Sexp
    last_value exp.last
  when :if
    then_clause = exp.then_clause
    else_clause = exp.else_clause

    if then_clause.nil? and else_clause.nil?
      nil
    elsif then_clause.nil?
      last_value else_clause
    elsif else_clause.nil?
      last_value then_clause
    else
      true_branch = last_value then_clause
      false_branch = last_value else_clause

      if true_branch and false_branch
        value = make_or(true_branch, false_branch)
        value.original_line = value.rhs.line
        value
      else #Unlikely?
        true_branch or false_branch
      end
    end
  when :lasgn, :iasgn, :op_asgn_or, :attrasgn
    last_value exp.rhs
  when :rescue
    values = []

    exp.each_sexp do |e|
      if node_type? e, :resbody
        if e.last
          values << last_value(e.last)
        end
      elsif sexp? e
        values << last_value(e)
      end
    end

    values.reject! do |v|
      v.nil? or node_type? v, :nil
    end

    if values.length > 1
      values.inject do |m, v|
        make_or(m, v)
      end
    else
      values.first
    end
  when :return
    if exp.value
      last_value exp.value
    else
      nil
    end
  when :nil
    nil
  else
    exp.original_line = exp.line unless exp.original_line
    exp
  end
end

#make_or(lhs, rhs) ⇒ Object


142
143
144
145
146
147
148
149
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 142

def make_or lhs, rhs
  #Better checks in future
  if lhs == rhs
    lhs
  else
    Sexp.new(:or, lhs, rhs)
  end
end

#make_return_valueObject

Turns the array of return values into an :or Sexp


152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 152

def make_return_value
  @return_values.compact!
  @return_values.uniq!

  if @return_values.empty?
    Sexp.new(:nil)
  elsif @return_values.length == 1
    @return_values.first
  else
    @return_values.reduce do |value, sexp|
      make_or value, sexp
    end
  end
end

#process_method(exp, env = nil) ⇒ Object

Process method (or, actually, any Sexp) for return value.


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 36

def process_method exp, env = nil
  exp = Brakeman::AliasProcessor.new.process_safely exp, env

  find_explicit_return_values exp

  if node_type? exp, :defn, :defs
    body = exp.body

    unless body.empty?
      @return_values << last_value(body)
    else
      Brakeman.debug "FindReturnValue: Empty method? #{exp.inspect}"
    end
  elsif exp
    @return_values << last_value(exp)
  else
     Brakeman.debug "FindReturnValue: Given something strange? #{exp.inspect}"
  end

  exp
end

#uses_ivars?Boolean

Returns:

  • (Boolean)

23
24
25
# File 'lib/brakeman/processors/lib/find_return_value.rb', line 23

def uses_ivars?
  @uses_ivars
end