def run_glslang_glsl_shader_to_spirv_shader( glsl_shader_path: pathlib.Path, output_dir_path: pathlib.Path, glslang_validator_file_path: Optional[pathlib.Path] = None, time_limit: int = GLSLANG_DEFAULT_TIME_LIMIT, ) -> pathlib.Path: if not glslang_validator_file_path: glslang_validator_file_path = util.tool_on_path( binaries_util.GLSLANG_VALIDATOR_NAME ) output_spirv_file_path = output_dir_path / (glsl_shader_path.name + ".spv") util.file_mkdirs_parent(output_spirv_file_path) subprocess_util.run( util.prepend_catchsegv_if_available( [ str(glslang_validator_file_path), "-V", "-o", str(output_spirv_file_path), str(glsl_shader_path), ] ), timeout=time_limit, ) return output_spirv_file_path
def run_spirv_opt_on_spirv_shader( input_spirv_file_path: pathlib.Path, output_dir_path: pathlib.Path, spirv_opt_args: List[str], spirv_opt_file_path: Optional[pathlib.Path] = None, spirv_opt_no_validate_after_all: bool = False, time_limit: int = SPIRV_OPT_DEFAULT_TIME_LIMIT, ) -> pathlib.Path: if not spirv_opt_file_path: spirv_opt_file_path = util.tool_on_path(binaries_util.SPIRV_OPT_NAME) output_spirv_file_path = output_dir_path / input_spirv_file_path.name util.file_mkdirs_parent(output_spirv_file_path) cmd = [ str(spirv_opt_file_path), str(input_spirv_file_path), "-o", str(output_spirv_file_path), ] if not spirv_opt_no_validate_after_all: cmd.append("--validate-after-all") cmd += spirv_opt_args cmd = util.prepend_catchsegv_if_available(cmd) subprocess_util.run(cmd, timeout=time_limit) return output_spirv_file_path
def run_spirv_val_on_shader( shader_path: Path, spirv_val_path: Path, extra_args: Optional[List[str]] = None, ) -> None: cmd = util.prepend_catchsegv_if_available([str(spirv_val_path), str(shader_path)]) if extra_args: cmd.extend(extra_args) subprocess_util.run(cmd)
def run_shader( shader_compiler_device: DeviceShaderCompiler, shader_path: Path, output_dir: Path, compiler_path: Path, timeout: int = DEFAULT_TIMEOUT, ) -> Path: output_file_path = output_dir / (shader_path.name + ".out") cmd = [str(compiler_path)] cmd += list(shader_compiler_device.args) cmd += [str(shader_path), "-o", str(output_file_path)] cmd = util.prepend_catchsegv_if_available(cmd) subprocess_util.run(cmd, verbose=True, timeout=timeout) return output_file_path
def run_spirv_dis_on_spirv_shader( input_spirv_file_path: pathlib.Path, output_dir_path: pathlib.Path, spirv_dis_file_path: Optional[pathlib.Path] = None, ) -> pathlib.Path: if not spirv_dis_file_path: spirv_dis_file_path = util.tool_on_path(binaries_util.SPIRV_DIS_NAME) output_spirv_file_path = output_dir_path / ( util.remove_end(input_spirv_file_path.name, ".spv") + ".asm") util.file_mkdirs_parent(output_spirv_file_path) subprocess_util.run( util.prepend_catchsegv_if_available([ str(spirv_dis_file_path), str(input_spirv_file_path), "-o", str(output_spirv_file_path), "--raw-id", ])) return output_spirv_file_path
def run_glslang_glsl_shader_to_spirv_shader( glsl_shader_path: pathlib.Path, output_dir_path: pathlib.Path, glslang_validator_file_path: Optional[pathlib.Path] = None, time_limit: int = GLSLANG_DEFAULT_TIME_LIMIT, preprocessor_cache: Optional[util.CommandCache] = None, ) -> pathlib.Path: if not glslang_validator_file_path: glslang_validator_file_path = util.tool_on_path( binaries_util.GLSLANG_VALIDATOR_NAME) output_spirv_file_path = output_dir_path / (glsl_shader_path.name + ".spv") util.file_mkdirs_parent(output_spirv_file_path) cmd = util.HashedCommand() cmd.append_program_path(glslang_validator_file_path) cmd.append_str("-V") cmd.append_str("-o") cmd.append_output_file(output_spirv_file_path) cmd.append_input_file(glsl_shader_path) if preprocessor_cache and preprocessor_cache.write_cached_output_file( cmd, output_spirv_file_path): return output_spirv_file_path cmd_str = util.prepend_catchsegv_if_available(cmd.cmd) subprocess_util.run( cmd_str, timeout=time_limit, ) if preprocessor_cache: preprocessor_cache.add_output_to_cache(cmd, output_spirv_file_path) return output_spirv_file_path
def run_spirv_opt_on_spirv_shader( input_spirv_file_path: pathlib.Path, output_dir_path: pathlib.Path, spirv_opt_args: List[str], spirv_opt_file_path: Optional[pathlib.Path] = None, spirv_opt_no_validate_after_all: bool = False, time_limit: int = SPIRV_OPT_DEFAULT_TIME_LIMIT, preprocessor_cache: Optional[util.CommandCache] = None, ) -> pathlib.Path: if not spirv_opt_file_path: spirv_opt_file_path = util.tool_on_path(binaries_util.SPIRV_OPT_NAME) output_spirv_file_path = output_dir_path / input_spirv_file_path.name util.file_mkdirs_parent(output_spirv_file_path) cmd = util.HashedCommand() cmd.append_program_path(spirv_opt_file_path) cmd.append_input_file(input_spirv_file_path) cmd.append_str("-o") cmd.append_output_file(output_spirv_file_path) if not spirv_opt_no_validate_after_all: cmd.append_str("--validate-after-all") cmd.extend_str(spirv_opt_args) if preprocessor_cache and preprocessor_cache.write_cached_output_file( cmd, output_spirv_file_path): return output_spirv_file_path cmd_str = util.prepend_catchsegv_if_available(cmd.cmd) subprocess_util.run(cmd_str, timeout=time_limit) if preprocessor_cache: preprocessor_cache.add_output_to_cache(cmd, output_spirv_file_path) return output_spirv_file_path
def main_helper( # pylint: disable=too-many-locals, too-many-branches, too-many-statements; settings_path: Path, iteration_seed_override: Optional[int] = None, fuzzing_tool_pattern: Optional[List[FuzzingTool]] = None, allow_no_stack_traces: bool = False, override_sigint: bool = True, use_amber_vulkan_loader: bool = False, active_device_names: Optional[List[str]] = None, update_ignored_crash_signatures_gerrit_cookie: Optional[str] = None, ) -> None: if not fuzzing_tool_pattern: fuzzing_tool_pattern = [FuzzingTool.GLSL_FUZZ] util.update_gcov_environment_variable_if_needed() if override_sigint: interrupt_util.override_sigint() try_get_root_file() settings = settings_util.read_or_create(settings_path) binary_manager = binaries_util.get_default_binary_manager( settings=settings) temp_dir = Path() / "temp" # Note: we use "is not None" so that if the user passes an empty Gerrit cookie, we still try to execute this code. if update_ignored_crash_signatures_gerrit_cookie is not None: git_tool = util.tool_on_path("git") downloaded_graphicsfuzz_tests_dir = ( temp_dir / f"graphicsfuzz_cts_tests_{get_random_name()[:8]}") work_dir = temp_dir / f"graphicsfuzz_cts_run_{get_random_name()[:8]}" download_cts_gf_tests.download_cts_graphicsfuzz_tests( git_tool=git_tool, cookie=update_ignored_crash_signatures_gerrit_cookie, output_tests_dir=downloaded_graphicsfuzz_tests_dir, ) download_cts_gf_tests.extract_shaders( tests_dir=downloaded_graphicsfuzz_tests_dir, binaries=binary_manager) with util.file_open_text(work_dir / "results.csv", "w") as results_out_handle: run_cts_gf_tests.main_helper( tests_dir=downloaded_graphicsfuzz_tests_dir, work_dir=work_dir, binaries=binary_manager, settings=settings, active_devices=devices_util.get_active_devices( settings.device_list), results_out_handle=results_out_handle, updated_settings_output_path=settings_path, ) return active_devices = devices_util.get_active_devices( settings.device_list, active_device_names=active_device_names) # Add host_preprocessor device from device list if it is missing. if not active_devices[0].HasField("preprocess"): for device in settings.device_list.devices: if device.HasField("preprocess"): active_devices.insert(0, device) break # Add host_preprocessor device (from scratch) if it is still missing. if not active_devices[0].HasField("preprocess"): active_devices.insert( 0, Device(name="host_preprocessor", preprocess=DevicePreprocess())) reports_dir = Path() / "reports" fuzz_failures_dir = reports_dir / FUZZ_FAILURES_DIR_NAME references_dir = Path() / REFERENCES_DIR donors_dir = Path() / DONORS_DIR spirv_fuzz_shaders_dir = Path() / "spirv_fuzz_shaders" # Log a warning if there is no tool on the PATH for printing stack traces. prepended = util.prepend_catchsegv_if_available([], log_warning=True) if not allow_no_stack_traces and not prepended: raise AssertionError("Stopping because we cannot get stack traces.") spirv_fuzz_shaders: List[Path] = [] references: List[Path] = [] if FuzzingTool.SPIRV_FUZZ in fuzzing_tool_pattern: check_dir_exists(spirv_fuzz_shaders_dir) spirv_fuzz_shaders = sorted(spirv_fuzz_shaders_dir.rglob("*.json")) if FuzzingTool.GLSL_FUZZ in fuzzing_tool_pattern: check_dir_exists(references_dir) check_dir_exists(donors_dir) # TODO: make GraphicsFuzz find donors recursively. references = sorted(references_dir.rglob("*.json")) # Filter to only include .json files that have at least one shader (.frag, .vert, .comp) file. references = [ ref for ref in references if shader_job_util.get_related_files(ref) ] if use_amber_vulkan_loader: library_path = binary_manager.get_binary_path_by_name( binaries_util.AMBER_VULKAN_LOADER_NAME).path.parent util.add_library_paths_to_environ([library_path], os.environ) fuzzing_tool_index = 0 while True: interrupt_util.interrupt_if_needed() # We have to use "is not None" because the seed could be 0. if iteration_seed_override is not None: iteration_seed = iteration_seed_override else: iteration_seed = secrets.randbits(ITERATION_SEED_BITS) log(f"Iteration seed: {iteration_seed}") random.seed(iteration_seed) staging_name = get_random_name()[:8] staging_dir = temp_dir / staging_name try: util.mkdir_p_new(staging_dir) except FileExistsError: if iteration_seed_override is not None: raise log(f"Staging directory already exists: {str(staging_dir)}") log("Starting new iteration.") continue # Pseudocode: # - Create test_dir(s) in staging directory. # - Run test_dir(s) on all active devices (stop early if appropriate). # - For each test failure on each device, copy the test to reports_dir, adding the device and crash signature. # - Reduce each report (on the given device). # - Produce a summary for each report. fuzzing_tool = fuzzing_tool_pattern[fuzzing_tool_index] fuzzing_tool_index = (fuzzing_tool_index + 1) % len(fuzzing_tool_pattern) if fuzzing_tool == FuzzingTool.SPIRV_FUZZ: fuzz_spirv_test.fuzz_spirv( staging_dir, reports_dir, fuzz_failures_dir, active_devices, spirv_fuzz_shaders, settings, binary_manager, ) elif fuzzing_tool == FuzzingTool.GLSL_FUZZ: fuzz_glsl_test.fuzz_glsl( staging_dir, reports_dir, fuzz_failures_dir, active_devices, references, donors_dir, settings, binary_manager, ) else: raise AssertionError(f"Unknown fuzzing tool: {fuzzing_tool}") if iteration_seed_override is not None: log("Stopping due to iteration_seed") break shutil.rmtree(staging_dir)
def run_amber_helper( amber_script_file: Path, output_dir: Path, dump_image: bool, dump_buffer: bool, amber_path: Path, skip_render: bool = False, debug_layers: bool = False, icd: Optional[Path] = None, ) -> Path: variant_image_file = output_dir / fuzz.VARIANT_IMAGE_FILE_NAME reference_image_file = output_dir / fuzz.REFERENCE_IMAGE_FILE_NAME buffer_file = output_dir / fuzz.BUFFER_FILE_NAME cmd = [ str(amber_path), str(amber_script_file), "--log-graphics-calls-time", "--disable-spirv-val", ] if not debug_layers: cmd.append("-d") if skip_render: # -ps tells amber to stop after pipeline creation cmd.append("-ps") else: if dump_image: cmd.append("-I") cmd.append("variant_framebuffer") cmd.append("-i") cmd.append(str(variant_image_file)) cmd.append("-I") cmd.append("reference_framebuffer") cmd.append("-i") cmd.append(str(reference_image_file)) if dump_buffer: cmd.append("-b") cmd.append(str(buffer_file)) cmd.append("-B") cmd.append("0") cmd = util.prepend_catchsegv_if_available(cmd) status = "UNEXPECTED_ERROR" result: Optional[types.CompletedProcess] = None env: Optional[Dict[str, str]] = None if icd: env = {"VK_ICD_FILENAMES": str(icd)} try: result = subprocess_util.run( cmd, check_exit_code=False, timeout=fuzz.AMBER_RUN_TIME_LIMIT, verbose=True, env=env, ) except subprocess.TimeoutExpired: status = fuzz.STATUS_TIMEOUT if result: if result.returncode != 0: status = fuzz.STATUS_CRASH else: status = fuzz.STATUS_SUCCESS log("\nSTATUS " + status + "\n") util.file_write_text(result_util.get_status_path(output_dir), status) return output_dir
def run_spirv_val_on_shader(shader_path: Path, spirv_val_path: Path) -> None: subprocess_util.run( util.prepend_catchsegv_if_available( [str(spirv_val_path), str(shader_path)]))
def main_helper( # pylint: disable=too-many-locals, too-many-branches, too-many-statements; settings_path: Path, iteration_seed_override: Optional[int], use_spirv_fuzz: bool, force_no_stack_traces: bool, ) -> None: util.update_gcov_environment_variable_if_needed() try: artifact_util.artifact_path_get_root() except FileNotFoundError: log( "Could not find ROOT file (in the current directory or above) to mark where binaries should be stored. " "Creating a ROOT file in the current directory." ) util.file_write_text(Path(artifact_util.ARTIFACT_ROOT_FILE_NAME), "") settings = settings_util.read_or_create(settings_path) active_devices = devices_util.get_active_devices(settings.device_list) reports_dir = Path() / "reports" fuzz_failures_dir = reports_dir / FUZZ_FAILURES_DIR_NAME temp_dir = Path() / "temp" references_dir = Path() / "references" donors_dir = Path() / "donors" spirv_fuzz_shaders_dir = Path() / "spirv_fuzz_shaders" # Log a warning if there is no tool on the PATH for printing stack traces. prepended = util.prepend_catchsegv_if_available([], log_warning=True) if not force_no_stack_traces and not prepended: raise AssertionError("Stopping because we cannot get stack traces.") spirv_fuzz_shaders: List[Path] = [] references: List[Path] = [] if use_spirv_fuzz: check_dir_exists(spirv_fuzz_shaders_dir) spirv_fuzz_shaders = sorted(spirv_fuzz_shaders_dir.rglob("*.json")) else: check_dir_exists(references_dir) check_dir_exists(donors_dir) # TODO: make GraphicsFuzz find donors recursively. references = sorted(references_dir.rglob("*.json")) # Filter to only include .json files that have at least one shader (.frag, .vert, .comp) file. references = [ ref for ref in references if shader_job_util.get_related_files(ref) ] binary_manager = binaries_util.get_default_binary_manager( settings=settings ).get_child_binary_manager(list(settings.custom_binaries), prepend=True) while True: # We have to use "is not None" because the seed could be 0. if iteration_seed_override is not None: iteration_seed = iteration_seed_override else: iteration_seed = secrets.randbits(ITERATION_SEED_BITS) log(f"Iteration seed: {iteration_seed}") random.seed(iteration_seed) staging_name = get_random_name()[:8] staging_dir = temp_dir / staging_name try: util.mkdir_p_new(staging_dir) except FileExistsError: if iteration_seed_override is not None: raise log(f"Staging directory already exists: {str(staging_dir)}") log(f"Starting new iteration.") continue # Pseudocode: # - Create test_dir(s) in staging directory. # - Run test_dir(s) on all active devices (stop early if appropriate). # - For each test failure on each device, copy the test to reports_dir, adding the device and crash signature. # - Reduce each report (on the given device). # - Produce a summary for each report. if use_spirv_fuzz: fuzz_spirv_test.fuzz_spirv( staging_dir, reports_dir, fuzz_failures_dir, active_devices, spirv_fuzz_shaders, settings, binary_manager, ) else: fuzz_glsl_test.fuzz_glsl( staging_dir, reports_dir, fuzz_failures_dir, active_devices, references, donors_dir, settings, binary_manager, ) shutil.rmtree(staging_dir) if iteration_seed_override is not None: log("Stopping due to iteration_seed") break