@@ -35,20 +35,21 @@ def _find_java_binaries(start_path, java_binaries):
35
35
_add_java_binary (full_pathname , java_binaries )
36
36
37
37
38
- def _read_info_of_class_files (class_files , temp_dir , verbosity ):
38
+ def _read_info_of_class_files (class_files , configuration , cmdline ):
39
+
39
40
assert isinstance (class_files , list ) and all (isinstance (s , str ) for s in class_files )
40
- class_list_json_file = os . path . join ( temp_dir , "collected_classes.json" )
41
+ class_list_json_file = configuration [ "collected_classes_path" ]
41
42
with open (class_list_json_file , "w" ) as ofile :
42
43
ofile .write (json .dumps (class_files , sort_keys = True , indent = 4 ))
43
- class_info_json_file = os .path .join (temp_dir , "collected_classes_info.json" )
44
+ class_info_json_file = configuration ["collected_classes_info_path" ]
45
+
44
46
os_command = (
45
47
analyser .get_java_class_info_tool_pathname () +
46
- " --in-json \" " + class_list_json_file + "\" " +
47
- " --out-json \" " + class_info_json_file + "\" "
48
+ " --configuration-path \" " + cmdline .prepare_scan + "\" "
48
49
)
49
50
prof_calling_java_class_info_start_time = time .time ()
50
51
print ("Invoking 'java-class-info' ..." )
51
- if verbosity >= 9 :
52
+ if cmdline . verbosity >= 9 :
52
53
print ("CWD: " + os .getcwd ())
53
54
print ("CMD: " + os_command )
54
55
os .system (os_command )
@@ -71,29 +72,32 @@ def _read_info_of_class_files(class_files, temp_dir, verbosity):
71
72
return classes_info , java_class_info_call_duration
72
73
73
74
74
- def collect_java_binaries (app_path , list_of_classpaths , entry_point , temp_dir , output_json , verbosity ):
75
+ def collect_java_binaries (cmdline ):
76
+ with open (cmdline .prepare_scan ) as config_file :
77
+ configuration = json .load (config_file )
78
+
75
79
prof_start_time = time .time ()
76
80
prof = dict ()
77
81
78
- if os .path .splitext (app_path )[1 ].lower () == ".war" :
82
+ if os .path .splitext (cmdline . input_path )[1 ].lower () == ".war" :
79
83
# Loading of WAR files is not supported yet in our front-end, see PR
80
84
# https://github.com/diffblue/cbmc/pull/608
81
85
# Therefore, we have to unpack them and collect Java binaries.
82
- unpack_dir = os .path .abspath (os .path .join (temp_dir , "WAR_UNPACK" ))
86
+ unpack_dir = os .path .abspath (os .path .join (cmdline . common_dir , "WAR_UNPACK" ))
83
87
assert not os .path .exists (unpack_dir )
84
88
os .makedirs (unpack_dir )
85
89
86
90
with utility .PushCwd (unpack_dir ):
87
- os .system ("jar xf " + app_path )
91
+ os .system ("jar xf " + cmdline . input_path )
88
92
89
- app_path = unpack_dir
93
+ cmdline . input_path = unpack_dir
90
94
91
95
java_binaries = CollectedJavaBinaries ()
92
- _find_java_binaries (app_path , java_binaries )
96
+ _find_java_binaries (cmdline . input_path , java_binaries )
93
97
94
98
library_directories = []
95
99
java_libraries = CollectedJavaBinaries ()
96
- for path in list_of_classpaths :
100
+ for path in cmdline . libraries :
97
101
if os .path .isdir (path ):
98
102
_find_java_binaries (path , java_libraries )
99
103
library_directories .append (path )
@@ -106,19 +110,17 @@ def collect_java_binaries(app_path, list_of_classpaths, entry_point, temp_dir, o
106
110
107
111
# First we read packages of all collected class files.
108
112
classes_info , java_class_info_call_duration = _read_info_of_class_files (
109
- java_binaries .class_files ,
110
- temp_dir ,
111
- verbosity
112
- )
113
+ java_binaries .class_files , configuration , cmdline )
114
+
113
115
prof ["java-class-info" ] = {"duration" : java_class_info_call_duration }
114
116
115
117
assert classes_info is not None and len (classes_info ["results" ]) != 0
116
118
117
119
# We copy classes into correct locations for the package structure
118
120
# inside the TEMP directory and pack them into a JAR file.
119
- classes_temp_dir = os .path .join (temp_dir , "CLASSES" )
120
- assert not os .path .exists (classes_temp_dir )
121
- os .makedirs (classes_temp_dir )
121
+ classes_temp_dir = os .path .join (cmdline . common_dir , "CLASSES" )
122
+ if not os .path .exists (classes_temp_dir ):
123
+ os .makedirs (classes_temp_dir )
122
124
123
125
for class_src_pathname , class_file_info in classes_info ["results" ].items ():
124
126
class_dst_pathname = os .path .join (classes_temp_dir , class_file_info ["name" ].replace ("." , "/" ) + ".class" )
@@ -135,23 +137,96 @@ def collect_java_binaries(app_path, list_of_classpaths, entry_point, temp_dir, o
135
137
# which causes multiple insertions of symbols from models library to the
136
138
# symbols table (because 'core-models' library is automatically added to
137
139
# each 'languaget' instance.
138
- java_binaries .jar_file = os .path .join (temp_dir , "collected_classes.jar" )
140
+ java_binaries .jar_file = os .path .join (cmdline . common_dir , "collected_classes.jar" )
139
141
with utility .PushCwd (classes_temp_dir ):
140
142
os .system ("jar cf \" " + java_binaries .jar_file + "\" ." )
141
143
142
- # We write the lists of collected Java binaries into the output JSON file.
143
- if not os .path .isdir (os .path .dirname (output_json )):
144
- os .makedirs (os .path .dirname (output_json ))
145
- with open (output_json , "w" ) as ofile :
144
+ entry_points_file = configuration ["detected_entry_points_path" ]
145
+ if not os .path .exists (entry_points_file ):
146
+ print ("WARNING: Unable to find any detected entry points. No analysis will be run." )
147
+ return
148
+
149
+ with open (entry_points_file ) as ep_config_file :
150
+ ep_config = json .load (ep_config_file )
151
+
152
+ # Copy the current commandline and transpose into a dictionary.
153
+ copied_command_line = {key .replace ("_" , "-" ): val for key , val in vars (cmdline ).items ()}
154
+
155
+ # Loop over all our detected entry points and create a folder for each.
156
+ class_paths = [p for p in java_binaries .classpath_jar_files + java_libraries .classpath_jar_files + library_directories ]
157
+ for ep_data in ep_config ["entry_points" ]:
158
+
159
+ method_data = ep_data ["method" ]
160
+
161
+ # We don't add the descriptor here as it's not recognized (and makes folder names too long).
162
+ fully_qualified_method = ep_data ["class_name" ] + "." + method_data ["name" ]
163
+
164
+ # Try to make sure the folder name isn't invalid.
165
+ folder_name = fully_qualified_method .replace (os .path .sep , '.' )
166
+ output_folder = os .path .join (cmdline .results_dir , folder_name )
167
+
168
+ # If our folder exists then just add (#number) to it and try creation again.
169
+ incrementor = 1
170
+ while os .path .exists (output_folder ):
171
+ folder_name = fully_qualified_method .replace (os .path .sep , '.' ) + " (" + str (incrementor ) + ")"
172
+ output_folder = os .path .join (cmdline .results_dir , folder_name )
173
+ incrementor += 1
174
+
175
+ os .mkdir (output_folder )
176
+
177
+ generated_temp_folder = os .path .join (cmdline .temp_dir , folder_name )
178
+
146
179
program_json = {
147
180
"jar" : java_binaries .jar_file ,
148
- "classpath" : [p for p in java_binaries .classpath_jar_files + java_libraries .classpath_jar_files + library_directories if os .path .exists (p )],
149
- "gbf" : os .path .join (temp_dir , "input_program.gbf" ), # The file should not exist yet. Here we only record the prefered/desired location
150
- # of the file on disk. Analyser will create it, if it does not exist (in the first run)
181
+ "classpath" : class_paths ,
182
+ # The file should not exist yet. Here we only record the prefered/desired location
183
+ # of the file on disk. Analyser will create it, if it does not exist (in the first run)
184
+ "gbf" : os .path .join (generated_temp_folder , "input_program.gbf" ),
185
+ "entry-point" : fully_qualified_method
186
+ }
187
+
188
+ program_file = os .path .join (output_folder , "program.json" )
189
+ with open (program_file , "w" ) as program_json_file :
190
+ json .dump (program_json , program_json_file , sort_keys = True , indent = 4 )
191
+
192
+ command_line_file = os .path .join (output_folder , "command_line.json" )
193
+
194
+ # Update our copied commandline with accurate / new values.
195
+ copied_command_line .update ({
196
+ "name" : "[" + cmdline .name + "] " + fully_qualified_method ,
197
+ "output-dir" : output_folder ,
198
+ "results-dir" : output_folder ,
199
+ "temp-dir" : generated_temp_folder ,
200
+ "entry-point" : fully_qualified_method
201
+ })
202
+
203
+ # Save the commandline file.
204
+ with open (command_line_file , "w" ) as commandline_json_file :
205
+ json .dump (copied_command_line , commandline_json_file , sort_keys = True , indent = 4 )
206
+
207
+ config_file = os .path .join (output_folder , "config.json" )
208
+
209
+ root_config_json = {
210
+ "program" : program_file ,
211
+ "rules" : cmdline .config ,
212
+ "timeout" : cmdline .timeout ,
213
+ "verbosity" : cmdline .verbosity ,
214
+ "dump_html_summaries" : cmdline .dump_html_summaries ,
215
+ "dump_html_statistics" : cmdline .dump_html_statistics ,
216
+ "dump_html_slice" : cmdline .dump_html_slice ,
217
+ "dump_html_program" : cmdline .dump_html_program ,
218
+ "do_not_use_precise_access_paths" : cmdline .do_not_use_precise_access_paths ,
219
+ "output-dir" : "./" ,
220
+ "temp-dir" : generated_temp_folder ,
221
+ "data-flow-insensitive-instrumentation" : cmdline .data_flow_insensitive_instrumentation ,
222
+ "lazy-methods-context-sensitive" : cmdline .lazy_methods_context_sensitive ,
223
+ "verify-csvsa-sparse-domains" : cmdline .verify_csvsa_sparse_domains ,
224
+ "use_goto_binary" : cmdline .use_goto_binary
151
225
}
152
- if entry_point is not None :
153
- program_json ["entry-point" ] = entry_point
154
- ofile .write (json .dumps (program_json , sort_keys = True , indent = 4 ))
226
+
227
+ # Save the config file.
228
+ with open (config_file , "w" ) as root_config_json_file :
229
+ json .dump (root_config_json , root_config_json_file , sort_keys = True , indent = 4 )
155
230
156
231
# Lastly, we complete and return statistics from this stage.
157
232
prof ["duration" ] = time .time () - prof_start_time
0 commit comments