flaw_detector 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ #ifndef VM_CORE_SUBSET_H
2
+ #define VM_CORE_SUBSET_H
3
+
4
+ /* to avoid warning */
5
+ struct rb_thread_struct;
6
+ struct rb_control_frame_struct;
7
+ typedef int rb_iseq_t;
8
+ typedef int rb_method_entry_t;
9
+
10
+ /* rb_call_info_t contains calling information including inline cache */
11
+ typedef struct rb_call_info_struct {
12
+ /* fixed at compile time */
13
+ ID mid;
14
+ VALUE flag;
15
+ int orig_argc;
16
+ rb_iseq_t *blockiseq;
17
+
18
+ /* inline cache: keys */
19
+ VALUE vmstat;
20
+ VALUE klass;
21
+
22
+ /* inline cache: values */
23
+ const rb_method_entry_t *me;
24
+ VALUE defined_class;
25
+
26
+ /* temporary values for method calling */
27
+ int argc;
28
+ struct rb_block_struct *blockptr;
29
+ VALUE recv;
30
+ union {
31
+ int opt_pc; /* used by iseq */
32
+ long index; /* used by ivar */
33
+ int missing_reason; /* used by method_missing */
34
+ int inc_sp; /* used by cfunc */
35
+ } aux;
36
+
37
+ VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci);
38
+ } rb_call_info_t;
39
+ typedef rb_call_info_t *CALL_INFO;
40
+
41
+ #define VM_CALL_ARGS_BLOCKARG (0x01 << 2) //copy from vm_core.h
42
+
43
+ #endif /* VM_CORE_SUBSET_H */
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.email = ["dbc.ginriki@gmail.com"]
10
10
  s.homepage = ""
11
11
  s.summary = %q{The tool to detect code's flaw with static analysis}
12
- s.description = %q{The tool detects code's flaw, which should be fixed, with static analysis of RubyVM bytecode. Therefore, it works for only ruby 1.9.x. ASAP, I will support ruby 2.0.x .}
12
+ s.description = %q{The tool detects code's flaw, which should be fixed, with static analysis of RubyVM bytecode. Therefore, it works for only ruby 1.9.x or 2.0.x .}
13
13
 
14
14
  s.rubyforge_project = "flaw detector"
15
15
 
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
  s.extensions = ["ext/insns_ext/extconf.rb"]
21
- s.required_ruby_version = "~> 1.9.0"
21
+ s.required_ruby_version = "> 1.9.0"
22
22
 
23
23
  # specify any dependencies here; for example:
24
24
  s.add_development_dependency "rspec"
data/lib/flaw_detector.rb CHANGED
@@ -6,6 +6,7 @@ require "flaw_detector/detector/nil_false_path_flow"
6
6
  require "flaw_detector/code_model/code_document"
7
7
  require "flaw_detector/code_model/insns_frame"
8
8
  require "flaw_detector/code_model/cfg_node"
9
+ require "flaw_detector/iseq/instruction_container"
9
10
  require File.expand_path("../../ext/insns_ext/insn_ext.rb", __FILE__)
10
11
 
11
12
  module FlawDetector
@@ -29,9 +30,17 @@ module FlawDetector
29
30
  INSNS_OF_BRANCH = ["branchif", "branchunless"]
30
31
 
31
32
  def parse(code_str, filepath="<compiled>")
32
- isqns = RubyVM::InstructionSequence.new(code_str)
33
- data = iseq_parse(isqns.to_a)
34
- CodeDocument.create(data, filepath)
33
+ tmp_compile_option = RubyVM::InstructionSequence.compile_option
34
+ doc = nil
35
+ begin
36
+ RubyVM::InstructionSequence.compile_option = false
37
+ isqns = RubyVM::InstructionSequence.compile(code_str)
38
+ data = iseq_parse(isqns.to_a)
39
+ doc = CodeDocument.create(data, filepath)
40
+ ensure
41
+ RubyVM::InstructionSequence.compile_option = tmp_compile_option
42
+ end
43
+ return doc
35
44
  end
36
45
 
37
46
  def parse_file(file)
@@ -81,16 +90,15 @@ module FlawDetector
81
90
  iseq[13].each do |mixed|
82
91
  case mixed
83
92
  when Array # instruction
84
- insns << mixed
93
+ insns << Iseq::InstructionContainer.new(mixed, header)
85
94
  opcode = mixed.first.to_s
86
95
  if INSNS_HAVE_ISEQ_IN_OPERAND.keys.include?(opcode)
87
- operand_num = INSNS_HAVE_ISEQ_IN_OPERAND[opcode]
88
- iseq_in_operand = iseq_parse(mixed[operand_num])
96
+ iseq_in_operand = iseq_parse(insns.last[:blockptr])
89
97
  insn_pos = insns.count-1
90
98
  insns_pos_to_operand_iseq[insn_pos] = iseq_in_operand
91
99
 
92
100
  #replace to link
93
- mixed[operand_num] = insn_pos
101
+ #mixed[operand_num] = insn_pos
94
102
 
95
103
  if insns_pos_to_operand_iseq[insn_pos] &&
96
104
  insns_pos_to_operand_iseq[insn_pos][:header][:type] == ISeqHeader::TYPE_BLOCK
@@ -42,13 +42,13 @@ module FlawDetector
42
42
  klass_specified_edge = nil
43
43
  case obj_insn[0]
44
44
  when :send
45
- if argnum == 0 && RCEV_KLASS_OF_METHODS.has_key?(obj_insn[1]) #varnum is the receiver and method is a nil check
45
+ if argnum == 0 && RCEV_KLASS_OF_METHODS.has_key?(obj_insn[:mid]) #varnum is the receiver and method is a nil check
46
46
  next_obj_index,next_argnum = frame.find_use_insn_index_of_ret(obj_index, obj_insn)
47
47
  next_obj_insn = frame.raw_block_data[:body][:insns][next_obj_index]
48
48
  case next_obj_insn[0]
49
49
  when :branchif, :branchunless
50
- klass_specified_edge = RCEV_KLASS_OF_METHODS[obj_insn[1]][:message][next_obj_insn[0]]
51
- klass = RCEV_KLASS_OF_METHODS[obj_insn[1]][:klass]
50
+ klass_specified_edge = RCEV_KLASS_OF_METHODS[obj_insn[:mid]][:message][next_obj_insn[0]]
51
+ klass = RCEV_KLASS_OF_METHODS[obj_insn[:mid]][:klass]
52
52
  end
53
53
  end
54
54
  when :branchif, :branchunless
@@ -120,8 +120,10 @@ module FlawDetector
120
120
  return result
121
121
  end
122
122
 
123
- # _variable_ :: nil variable on node
124
- # return: check_end?, detected ngs
123
+ # @param variable [Hash] nil variable on node
124
+ # @return [Boolean] check_end?
125
+ # @return [Array] detected ngs
126
+ # @todo remove false positive detection of neither compareable or replacement operator such as "<<"
125
127
  def check_nil_var_ref(node, variable)
126
128
  ng_list = [] # each element has keys: {:variable, :index, :frame}
127
129
  unless node.prev_nodes.first == node.prev_nodes.last
@@ -147,8 +149,8 @@ module FlawDetector
147
149
  use_insn = frame.insns[use_index]
148
150
  case use_insn[0]
149
151
  when :send
150
- use_insn[1]
151
- if use_argnum == 0 && !NIL_METHODS.include?(use_insn[1])
152
+ if (use_argnum == 0 && !NIL_METHODS.include?(use_insn[:mid])) ||
153
+ (use_argnum == 1 && CALC_CODE.values.include?(use_insn[:mid]) && !NIL_METHODS.include?(use_insn[:mid]))
152
154
  ng_list << {:variable => variable, :index => use_index, :frame => frame}
153
155
  end
154
156
  when *(CALC_CODE.keys)
@@ -0,0 +1,83 @@
1
+ module FlawDetector
2
+ module Iseq
3
+ class InstructionContainer
4
+ attr_reader :insn
5
+ def initialize(insn, header)
6
+ @insn = insn
7
+ @major_version = header[:major]
8
+ end
9
+
10
+ def major_version
11
+ @major_version
12
+ end
13
+
14
+ def inspect
15
+ @insn.inspect
16
+ end
17
+
18
+ def [](param)
19
+ case param
20
+ when Fixnum
21
+ return @insn[param]
22
+ when Range
23
+ return @insn[param]
24
+ when Symbol
25
+ if param == :opcode
26
+ return @insn[0]
27
+ else
28
+ return send("symbol_#{self[:opcode]}_v#{self.major_version}", param)
29
+ end
30
+ else
31
+ raise "unknown param:#{param}"
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def symbol_send_v1(param)
38
+ case param
39
+ when :mid
40
+ return @insn[1]
41
+ when :blockptr
42
+ return @insn[3]
43
+ end
44
+ end
45
+
46
+ def symbol_send_v2(param)
47
+ case param
48
+ when :mid
49
+ return @insn[1][:mid]
50
+ when :blockptr
51
+ return @insn[1][:blockptr]
52
+ else
53
+ return symbol_send_v1(param)
54
+ end
55
+ end
56
+
57
+ def symbol_putiseq_v1(param)
58
+ case param
59
+ when :blockptr
60
+ return @insn[1]
61
+ end
62
+ end
63
+
64
+ def symbol_defineclass_v1(param)
65
+ case param
66
+ when :blockptr
67
+ return @insn[2]
68
+ end
69
+ end
70
+
71
+ def symbol_invokesuper_v1(param)
72
+ case param
73
+ when :blockptr
74
+ return @insn[2]
75
+ end
76
+ end
77
+
78
+ alias :symbol_invokesuper_v2 :symbol_invokesuper_v1
79
+ alias :symbol_putiseq_v2 :symbol_putiseq_v1
80
+ alias :symbol_defineclass_v2 :symbol_defineclass_v1
81
+ end
82
+ end
83
+ end
@@ -11,9 +11,9 @@ module FlawDetector
11
11
  :details => "This method contains a redundant check of a known false value against the constant false."
12
12
  },
13
13
  "RCN_REDUNDANT_FALSECHECK_OF_TRUE_VALUE" => {
14
- :short_desc => "Redundant falsecheck of value known to be false",
15
- :long_desc => "Redundant falsecheck of %{0} which is known to be false in LINE:%{1}",
16
- :details => "This method contains a redundant check of a known false value against the constant false."
14
+ :short_desc => "Redundant falsecheck of value known to be true",
15
+ :long_desc => "Redundant falsecheck of %{0} which is known to be true in LINE:%{1}",
16
+ :details => "This method contains a redundant check of a true value against the constant false."
17
17
  },
18
18
  "NP_ALWAYS_FALSE" => {
19
19
  :short_desc => "False value missing method received",
@@ -1,3 +1,3 @@
1
1
  module FlawDetector
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,38 +1,39 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: flaw_detector
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
6
5
  platform: ruby
7
- authors:
6
+ authors:
8
7
  - Rikiya Ayukawa
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
-
13
- date: 2013-04-28 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
11
+ date: 2013-06-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
16
14
  name: rspec
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
24
20
  type: :development
25
- version_requirements: *id001
26
- description: The tool detects code's flaw, which should be fixed, with static analysis of RubyVM bytecode. Therefore, it works for only ruby 1.9.x. ASAP, I will support ruby 2.0.x .
27
- email:
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: The tool detects code's flaw, which should be fixed, with static analysis
28
+ of RubyVM bytecode. Therefore, it works for only ruby 1.9.x or 2.0.x .
29
+ email:
28
30
  - dbc.ginriki@gmail.com
29
- executables:
31
+ executables:
30
32
  - flaw_detector
31
- extensions:
33
+ extensions:
32
34
  - ext/insns_ext/extconf.rb
33
35
  extra_rdoc_files: []
34
-
35
- files:
36
+ files:
36
37
  - .gitignore
37
38
  - .travis.yml
38
39
  - Gemfile
@@ -42,9 +43,15 @@ files:
42
43
  - bin/flaw_detector
43
44
  - ext/insns_ext/extconf.rb
44
45
  - ext/insns_ext/insn_ext.rb
45
- - ext/insns_ext/insns.inc
46
- - ext/insns_ext/insns_ext.c
47
- - ext/insns_ext/insns_info.inc
46
+ - ext/insns_ext/insns/1.9/BSDL
47
+ - ext/insns_ext/insns/1.9/insns.inc
48
+ - ext/insns_ext/insns/1.9/insns_ext.c
49
+ - ext/insns_ext/insns/1.9/insns_info.inc
50
+ - ext/insns_ext/insns/2.0/BSDL
51
+ - ext/insns_ext/insns/2.0/insns.inc
52
+ - ext/insns_ext/insns/2.0/insns_ext.c
53
+ - ext/insns_ext/insns/2.0/insns_info.inc
54
+ - ext/insns_ext/insns/2.0/vm_core_subset.h
48
55
  - flaw_detector.gemspec
49
56
  - lib/flaw_detector.rb
50
57
  - lib/flaw_detector/code_model/cfg_node.rb
@@ -54,39 +61,35 @@ files:
54
61
  - lib/flaw_detector/detector/abstract_detector.rb
55
62
  - lib/flaw_detector/detector/nil_false_path_flow.rb
56
63
  - lib/flaw_detector/formatter/csv_formatter.rb
64
+ - lib/flaw_detector/iseq/instruction_container.rb
57
65
  - lib/flaw_detector/message.rb
58
66
  - lib/flaw_detector/version.rb
59
67
  - sample/flaw_in_code.rb
60
68
  - spec/lib/flaw_detector_spec.rb
61
69
  - spec/spec_helper.rb
62
- homepage: ""
70
+ homepage: ''
63
71
  licenses: []
64
-
72
+ metadata: {}
65
73
  post_install_message:
66
74
  rdoc_options: []
67
-
68
- require_paths:
75
+ require_paths:
69
76
  - lib
70
- required_ruby_version: !ruby/object:Gem::Requirement
71
- none: false
72
- requirements:
73
- - - ~>
74
- - !ruby/object:Gem::Version
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '>'
80
+ - !ruby/object:Gem::Version
75
81
  version: 1.9.0
76
- required_rubygems_version: !ruby/object:Gem::Requirement
77
- none: false
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
82
87
  requirements: []
83
-
84
88
  rubyforge_project: flaw detector
85
- rubygems_version: 1.8.12
89
+ rubygems_version: 2.0.2
86
90
  signing_key:
87
- specification_version: 3
91
+ specification_version: 4
88
92
  summary: The tool to detect code's flaw with static analysis
89
- test_files:
93
+ test_files:
90
94
  - spec/lib/flaw_detector_spec.rb
91
95
  - spec/spec_helper.rb
92
- has_rdoc: