flaw_detector 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +62 -2
- data/ext/insns_ext/extconf.rb +1 -1
- data/ext/insns_ext/insn_ext.rb +33 -1
- data/ext/insns_ext/insns/1.9/BSDL +22 -0
- data/ext/insns_ext/{insns.inc → insns/1.9/insns.inc} +0 -0
- data/ext/insns_ext/{insns_ext.c → insns/1.9/insns_ext.c} +0 -0
- data/ext/insns_ext/{insns_info.inc → insns/1.9/insns_info.inc} +10 -10
- data/ext/insns_ext/insns/2.0/BSDL +22 -0
- data/ext/insns_ext/insns/2.0/insns.inc +187 -0
- data/ext/insns_ext/insns/2.0/insns_ext.c +36 -0
- data/ext/insns_ext/insns/2.0/insns_info.inc +724 -0
- data/ext/insns_ext/insns/2.0/vm_core_subset.h +43 -0
- data/flaw_detector.gemspec +2 -2
- data/lib/flaw_detector.rb +15 -7
- data/lib/flaw_detector/detector/nil_false_path_flow.rb +9 -7
- data/lib/flaw_detector/iseq/instruction_container.rb +83 -0
- data/lib/flaw_detector/message.rb +3 -3
- data/lib/flaw_detector/version.rb +1 -1
- metadata +49 -46
@@ -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 */
|
data/flaw_detector.gemspec
CHANGED
@@ -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
|
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 = "
|
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
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
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[
|
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[
|
51
|
-
klass = RCEV_KLASS_OF_METHODS[obj_insn[
|
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
|
-
#
|
124
|
-
# return
|
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[
|
151
|
-
|
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
|
15
|
-
:long_desc => "Redundant falsecheck of %{0} which is known to be
|
16
|
-
:details => "This method contains a redundant check of a
|
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",
|
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
|
-
|
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
|
-
|
14
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
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.
|
46
|
-
- ext/insns_ext/
|
47
|
-
- ext/insns_ext/
|
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
|
-
|
72
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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:
|
89
|
+
rubygems_version: 2.0.2
|
86
90
|
signing_key:
|
87
|
-
specification_version:
|
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:
|