3030
3131def run_experiment (project_name , target_name , args , output_path ,
3232 build_output_path , upload_corpus_path , upload_coverage_path ,
33- experiment_name ):
33+ experiment_name , upload_reproducer_path ):
3434 config = build_project .Config (testing = True ,
3535 test_image_suffix = '' ,
3636 repo = build_project .DEFAULT_OSS_FUZZ_REPO ,
@@ -74,8 +74,12 @@ def run_experiment(project_name, target_name, args, output_path,
7474 local_output_path = '/workspace/output.log'
7575 local_corpus_path_base = '/workspace/corpus'
7676 local_corpus_path = os .path .join (local_corpus_path_base , target_name )
77+ default_target_path = os .path .join (build .out , target_name )
78+ local_target_dir = os .path .join (build .out , 'target' )
7779 local_corpus_zip_path = '/workspace/corpus/corpus.zip'
78- fuzzer_args = ' ' .join (args )
80+ local_artifact_path = os .path .join (build .out , 'artifacts/' )
81+ local_stacktrace_path = os .path .join (build .out , 'stacktrace/' )
82+ fuzzer_args = ' ' .join (args + [f'-artifact_prefix={ local_artifact_path } ' ])
7983
8084 env = build_project .get_env (project_yaml ['language' ], build )
8185 env .append ('RUN_FUZZER_MODE=batch' )
@@ -90,6 +94,9 @@ def run_experiment(project_name, target_name, args, output_path,
9094 'bash' ,
9195 '-c' ,
9296 (f'mkdir -p { local_corpus_path } && '
97+ f'mkdir -p { local_target_dir } && '
98+ f'mkdir -p { local_artifact_path } && '
99+ f'mkdir -p { local_stacktrace_path } && '
93100 f'run_fuzzer { target_name } { fuzzer_args } '
94101 f'|& tee { local_output_path } || true' ),
95102 ]
@@ -115,6 +122,60 @@ def run_experiment(project_name, target_name, args, output_path,
115122 ],
116123 })
117124
125+ if upload_reproducer_path :
126+ # Upload binary. First copy the binary directly from default_target_path,
127+ # if that fails, find it under build out dir and copy to local_target_dir.
128+ # If either succeeds, then upload it to bucket.
129+ # If multiple files are found, suffix them and upload them all.
130+ steps .append ({
131+ 'name' :
132+ 'gcr.io/cloud-builders/gsutil' ,
133+ 'entrypoint' :
134+ '/bin/bash' ,
135+ 'args' : [
136+ '-c' ,
137+ (f'cp { default_target_path } { local_target_dir } 2>/dev/null || '
138+ f'find { build .out } -type f -name { target_name } -exec bash -c '
139+ f'\' cp "$0" "{ local_target_dir } /$(echo "$0" | sed "s@/@_@g")"\' '
140+ f'{{}} \\ ; && gsutil cp -r { local_target_dir } '
141+ f'{ upload_reproducer_path } /{ target_name } || true' ),
142+ ],
143+ })
144+
145+ # Upload reproducer.
146+ steps .append ({
147+ 'name' :
148+ 'gcr.io/cloud-builders/gsutil' ,
149+ 'entrypoint' :
150+ '/bin/bash' ,
151+ 'args' : [
152+ '-c' ,
153+ (f'gsutil -m cp -r { local_artifact_path } { upload_reproducer_path } '
154+ '|| true' ),
155+ ],
156+ })
157+
158+ # Upload stacktrace.
159+ steps .append ({
160+ 'name' :
161+ 'gcr.io/cloud-builders/gsutil' ,
162+ 'entrypoint' :
163+ '/bin/bash' ,
164+ 'args' : [
165+ '-c' ,
166+ (f'if [ -f { local_target_dir } /{ target_name } ]; then '
167+ f'{ local_target_dir } /{ target_name } { local_artifact_path } /* > '
168+ f'{ local_stacktrace_path } /{ target_name } .st 2>&1; '
169+ 'else '
170+ f'for target in { local_target_dir } /*; do '
171+ f'"$target" { local_artifact_path } /* > '
172+ f'"{ local_stacktrace_path } /$target.st" 2>&1; '
173+ 'done; fi; '
174+ f'gsutil -m cp -r { local_stacktrace_path } { upload_reproducer_path } '
175+ ' || true' ),
176+ ],
177+ })
178+
118179 # Build for coverage.
119180 build = build_project .Build ('libfuzzer' , 'coverage' , 'x86_64' )
120181 env = build_project .get_env (project_yaml ['language' ], build )
@@ -213,6 +274,10 @@ def main():
213274 parser .add_argument ('--upload_corpus' ,
214275 required = True ,
215276 help = 'GCS location to upload corpus.' )
277+ parser .add_argument ('--upload_reproducer' ,
278+ required = False ,
279+ default = '' ,
280+ help = 'GCS location to upload reproducer.' )
216281 parser .add_argument ('--upload_coverage' ,
217282 required = True ,
218283 help = 'GCS location to upload coverage data.' )
@@ -223,7 +288,8 @@ def main():
223288
224289 run_experiment (args .project , args .target , args .args , args .upload_output_log ,
225290 args .upload_build_log , args .upload_corpus ,
226- args .upload_coverage , args .experiment_name )
291+ args .upload_coverage , args .experiment_name ,
292+ args .upload_reproducer )
227293
228294
229295if __name__ == '__main__' :
0 commit comments