spirvsmith
A differential testing tool targeting SPIRV based on structured fuzzing techniques
Science Score: 54.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
✓CITATION.cff file
Found CITATION.cff file -
✓codemeta.json file
Found codemeta.json file -
✓.zenodo.json file
Found .zenodo.json file -
○DOI references
-
✓Academic publication links
Links to: zenodo.org -
○Academic email domains
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (14.1%) to scientific vocabulary
Keywords
Repository
A differential testing tool targeting SPIRV based on structured fuzzing techniques
Basic Info
Statistics
- Stars: 15
- Watchers: 3
- Forks: 2
- Open Issues: 5
- Releases: 12
Topics
Metadata Files
README.md
SPIRVSmith
SPIRVSmith
SPIRVSmith is a differential testing tool that leverages structured fuzzing techniques to find bugs in producers and consumers of SPIRV shaders.
SPIRVSmith attempts to find bugs in the following projects: - SPIRV-Tools - mostly the validator and reducer components. - SPIRV-Cross - Amber - SwiftShader - MoltenVK - ...and more to come!
Table of Contents
Installation
SPIRVSmith uses poetry to manage Python dependencies and ships with scripts to install external dependencies.
Follow the poetry installation instructions for your platform.
Grab a local copy of SPIRVSmith:
bash
$ git clone https://github.com/rayanht/SPIRVSmith.git && cd SPIRVSmith
- Install Python dependencies using
poetryand start apoetryshell:
bash
$ poetry install && poetry shell
- Install the external dependencies:
bash
$ mkdir bin
$ sh scripts/get_spirv_tools.sh <platform>
Replace <platform> by either linux or macos (No support for Windows :sob:)
Usage
The first step is to run SPIRVSmith is to head to config.py. That file contains the various parameters that are used to dictate the behaviour of the fuzzer.
SPIRVSmith is highly parametrizable, you can choose to disable certain features of the SPIR-V language (e.g. do not emit any control flow operation), limit the number of global constants generated, favour the generation of certain kinds of instructions etc.
Once you are happy with your parametrization, make sure you are in a poetry virtual environment ($ poetry shell) and run SPIRVSmith:
bash
$ sh scripts/run.sh
SPIR-V assembly files will be saved as they are generated to the out/ directory and the fuzzer can be stopped at any time by pressing Ctrl+C.
How does it work?
Differential Testing
The bread and butter of SPIRVSmith is differential testing (sometimes called differential fuzzing), in which we provide the same SPIRV shader to similar consumers (say three different SPIRV compilers for example), execute the three resulting programs and compare the values contained inside all buffers at the end of exeuction.
In a fully deterministic program (== synchronous && free of undefined behaviour), we expect all these buffers to be exactly the same at the end of execution, regardless of what compiler was used to generate said program. If one program ends up with different buffers than the other two, we have a strong reason to believe that the compiler that generated it has a bug.
This concept can be extended further by varying the platform that executes the shader. If we get different results by running the same shader on an Nvidia GPU, an AMD GPU, and an Intel integrated graphics chip then there is a good chance that either the underlying Vulkan engine or the GPU driver has a bug (possibly both).
The constraint on determinism creates an interesting problem, how can we ensure that the randomly generated programs are free of undefined behaviour? Unlike existing differential testing tools, SPIRVSmith does not perform any static analysis or backtracking at generation-time to enforce this constraint, we rather implement the idea of program reconditioning by Donaldson et al.
Program Reconditioning
Donaldson et al. introduce the idea of program reconditioning as "a method for leveraging off-the-shelf test case reducers to simplify programs that expose miscompilation bugs during randomised differential testing".
This approach solves the issues raised by Yang et al. in the case of CSmith where test case reducers couldn't be used to provide concise, actionable bug reports since they would themselves often introduce undefined behaviour.
Program reconditioning works by decoupling the process of generating a program and the process of ensuring that said program is free of undefined behaviour. This is in contrast to Livinskii et al. in YARPGen where code generation steps and static analysis steps are interleaved.
Donaldson et al. describe a rule-based reconditioning approach where transforms are applied to constructs that could exhibit undefined behaviour. Transforms are applied to all eligible construct in a blanket manner, no static analysis is performed to determine which constructs are in fact worth reconditioning. Here is example of reconditioning a GLSL shader:
Original
glsl
float A [3]; // Not initialised
void main () {
int i = int (A[0]);
float f = 2000000.0;
while (i != -42) { // Might not terminate
A[i] = f; // Out of bounds ?
f = f + f; // Roundoff
int j = i ++ + ( i / ( i - 1)); // Order of side effects, divide by zero?
i = j;
}
}
Reconditioned
glsl
// [ Declarations of SAFE_ABS , MAKE_IN_RANGE and SAFE_DIV ]
uint _loop_count = 0u;
const uint _loop_limit = 100u;
float A [3] = float [3](1.0 , 1.0 , 1.0);
void main () {
int i = int (A[0]);
float f = 2000000.0;
while (i != -42) {
if (_loop_count >= _loop_limit) break;
_loop_count ++;
A[SAFE_ABS(i) % 3] = f ;
f = MAKE_IN_RANGE(f + f);
int _t = SAFE_DIV(i , i - 1);
int j = i ++ + _t;
i = j;
}
}
SPIRV Language Coverage
Expand
### Instructions #### MiscellanousExpand
|OpCode| Status | |--|--| | OpNop | :red_circle: | | OpUndef | :red_circle: | | OpSizeOf | :red_circle: |Debug
Expand
|OpCode| Status | |--|--| | OpSourceContinued | :red_circle: | | OpSource | :red_circle: | | OpSourceExtension | :red_circle: | | OpName | :red_circle: | | OpMemberName | :red_circle: | | OpString | :red_circle: | | OpLine | :red_circle: | | OpNoLine | :red_circle: | | OpModuleProcessed | :red_circle: |Annotation
Expand
|OpCode| Status | |--|--| | OpDecorate | :white_check_mark: | | OpMemberDecorate | :white_check_mark: | | OpDecorationGroup | :red_circle: | | OpGroupDecorate | :red_circle: | | OpGroupMemberDecorate | :red_circle: | | OpDecorateId | :red_circle: | | OpDecorateString | :red_circle: | | OpMemberDecorateString | :red_circle: |Extension
Expand
|OpCode| Status | |--|--| | OpExtension | :white_check_mark: | | OpExtInstImport | :white_check_mark: | | OpExtInst | :white_check_mark: |Mode-Setting
Expand
|OpCode| Status | |--|--| | OpMemoryModel | :white_check_mark: | | OpEntryPoint | :white_check_mark: | | OpExecutionMode | :white_check_mark: | | OpCapability | :white_check_mark: | | OpExecutionModeId | :red_circle: |Type-Declaration
Expand
|OpCode| Status | |--|--| | OpTypeVoid | :white_check_mark: | | OpTypeBool | :white_check_mark: | | OpTypeInt | :white_check_mark: | | OpTypeFloat | :white_check_mark: | | OpTypeVector | :white_check_mark: | | OpTypeMatrix | :white_check_mark: | | OpTypeImage | :red_circle: | | OpTypeSampler | :red_circle: | | OpTypeSampledImage | :red_circle: | | OpTypeArray | :white_check_mark: | | OpTypeRuntimeArray | :red_circle: | | OpTypeStruct | :white_check_mark: | | OpTypeOpaque | :red_circle: | | OpTypePointer | :white_check_mark: | | OpTypeFunction | :white_check_mark: |Constant-Creation
Expand
|OpCode| Status | |--|--| | OpConstantTrue | :white_check_mark: | | OpConstantFalse | :white_check_mark: | | OpConstant | :white_check_mark: | | OpConstantComposite | :white_check_mark: | | OpConstantSampler | :red_circle: | | OpConstantNull | :red_circle: | | OpSpecConstantTrue | :red_circle: | | OpSpecConstantFalse | :red_circle: | | OpSpecConstant | :red_circle: | | OpSpecConstantComposite | :red_circle: | | OpSpecConstantOp | :red_circle: |Memory
Expand
|OpCode| Status | |--|--| | OpVariable | :white_check_mark: | | OpImageTexelPointer | :red_circle: | | OpLoad | :white_check_mark: | | OpStore |:white_check_mark: | | OpCopyMemory | :red_circle: | | OpCopyMemorySized | :red_circle: | | OpAccessChain | :white_check_mark: | | OpInBoundsAccessChain | :red_circle: | | OpPtrAccessChain | :red_circle: | | OpPtrEqual | :red_circle: | | OpPtrNotEqual | :red_circle: | | OpPtrDiff | :red_circle: |Function
Expand
|OpCode| Status | |--|--| | OpFunction | :white_check_mark: | | OpFunctionParameter | :white_check_mark: | | OpFunctionEnd | :white_check_mark: | | OpFunctionCall | :red_circle: |Image
Expand
|OpCode| Status | |--|--| | OpSampledImage | :red_circle: | | OpImageSampleImplicitLod | :red_circle: | | OpImageSampleExplicitLod | :red_circle: | | OpImageSampleDrefImplicitLod |:red_circle: | | OpImageSampleDrefExplicitLod | :red_circle: | | OpImageSampleProjImplicitLod | :red_circle: | | OpImageSampleProjExplicitLod | :red_circle: | | OpImageSampleProjDrefImplicitLod | :red_circle: | | OpImageSampleProjDrefExplicitLod | :red_circle: | | OpImageFetch | :red_circle: | | OpImageGather | :red_circle: | | OpImageDrefGather | :red_circle: | | OpImageRead | :red_circle: | | OpImageWrite | :red_circle: | | OpImage | :red_circle: | | OpImageQueryFormat | :red_circle: | | OpImageQueryOrder | :red_circle: | | OpImageQuerySizeLod | :red_circle: | | OpImageQuerySize | :red_circle: | | OpImageQueryLod | :red_circle: | | OpImageQueryLevels | :red_circle: | | OpImageQuerySamples | :red_circle: | | OpImageSparseSampleImplicitLod | :red_circle: | | OpImageSparseSampleExplicitLod | :red_circle: | | OpImageSparseSampleDrefImplicitLod | :red_circle: | | OpImageSparseSampleDrefExplicitLod | :red_circle: | | OpImageSparseFetch | :red_circle: | | OpImageSparseGather | :red_circle: | | OpImageSparseDrefGather | :red_circle: | | OpImageSparseTexelsResident | :red_circle: | | OpImageSparseRead | :red_circle: |Conversion
Expand
|OpCode| Status | |--|--| | OpConvertFToU | :white_check_mark: | | OpConvertFToS | :white_check_mark: | | OpConvertSToF | :white_check_mark: | | OpConvertUToF | :white_check_mark: | | OpUConvert | :red_circle: | | OpSConvert | :red_circle: | | OpFConvert | :red_circle: | | OpQuantizeToF16 | :red_circle: | | OpConvertPtrToU | :red_circle: | | OpSatConvertSToU | :red_circle: | | OpSatConvertUToS | :red_circle: | | OpConvertUToPtr | :red_circle: | | OpPtrCastToGeneric | :red_circle: | | OpGenericCastToPtr | :red_circle: | | OpGenericCastToPtrExplicit | :red_circle: | | OpBitcast | :red_circle: |Composite
Expand
|OpCode| Status | |--|--| | OpVectorExtractDynamic | :white_check_mark: | | OpVectorInsertDynamic | :white_check_mark: | | OpVectorShuffle | :white_check_mark: | | OpCompositeConstruct | :red_circle: | | OpCompositeExtract | :white_check_mark: | | OpCompositeInsert | :white_check_mark: | | OpCopyObject | :white_check_mark: | | OpTranspose | :white_check_mark: | | OpCopyLogical | :red_circle: |Arithmetic
Expand
|OpCode| Status | |--|--| | OpSNegate | :white_check_mark: | | OpFNegate | :white_check_mark: | | OpIAdd | :white_check_mark: | | OpFAdd | :white_check_mark: | | OpISub | :white_check_mark: | | OpFSub | :white_check_mark: | | OpIMul | :white_check_mark: | | OpFMul | :white_check_mark: | | OpUDiv | :white_check_mark: | | OpSDiv | :white_check_mark: | | OpFDiv | :white_check_mark: | | OpUMod | :white_check_mark: | | OpSRem | :white_check_mark: | | OpSMod | :white_check_mark: | | OpFRem | :white_check_mark: | | OpFMod | :white_check_mark: | | OpVectorTimesScalar | :white_check_mark: | | OpMatrixTimesScalar | :white_check_mark: | | OpVectorTimesMatrix | :white_check_mark: | | OpMatrixTimesVector | :white_check_mark: | | OpMatrixTimesMatrix | :white_check_mark: | | OpOuterProduct | :white_check_mark: | | OpDot | :white_check_mark: | | OpIAddCarry | :red_circle: | | OpISubBorrow | :red_circle: | | OpUMulExtended | :red_circle: | | OpSMulExtended | :red_circle: |Bit
Expand
|OpCode| Status | |--|--| | OpShiftRightLogical | :white_check_mark: | | OpShiftRightArithmetic | :white_check_mark: | | OpShiftLeftLogical | :white_check_mark: | | OpBitwiseOr |:white_check_mark: | | OpBitwiseXor | :white_check_mark: | | OpBitwiseAnd | :white_check_mark: | | OpNot | :white_check_mark: | | OpBitFieldInsert | :white_check_mark: | | OpBitFieldSExtract | :white_check_mark: | | OpBitFieldUExtract | :white_check_mark: | | OpBitReverse | :white_check_mark: | | OpBitCount | :white_check_mark: |Relational and Logical
Expand
|OpCode| Status | |--|--| | OpAny | :white_check_mark: | | OpAll | :white_check_mark: | | OpIsNan | :white_check_mark: | | OpIsInf |:white_check_mark: | | OpIsFinite | :red_circle: | | OpIsNormal | :red_circle: | | OpSignBitSet | :red_circle: | | OpOrdered | :red_circle: | | OpUnordered | :red_circle: | | OpLogicalEqual | :white_check_mark: | | OpLogicalNotEqual | :white_check_mark: | | OpLogicalOr | :white_check_mark: | | OpLogicalAnd | :white_check_mark: | | OpLogicalNot | :white_check_mark: | | OpSelect |:white_check_mark: | | OpIEqual | :white_check_mark: | | OpINotEqual | :white_check_mark: | | OpUGreaterThan | :white_check_mark: | | OpSGreaterThan | :white_check_mark: | | OpUGreaterThanEqual | :white_check_mark: | | OpSGreaterThanEqual | :white_check_mark: | | OpULessThan | :white_check_mark: | | OpSLessThan | :white_check_mark: | | OpULessThanEqual | :white_check_mark: | | OpSLessThanEqual | :white_check_mark: | | OpFOrdEqual | :white_check_mark: | | OpFUnordEqual | :white_check_mark: | | OpFOrdNotEqual | :white_check_mark: | | OpFUnordNotEqual | :white_check_mark: | | OpFOrdLessThan | :white_check_mark: | | OpFUnordLessThan | :white_check_mark: | | OpFOrdGreaterThan | :white_check_mark: | | OpFUnordGreaterThan | :white_check_mark: | | OpFOrdLessThanEqual | :white_check_mark: | | OpFUnordLessThanEqual | :white_check_mark: | | OpFOrdGreaterThanEqual | :white_check_mark: | | OpFUnordGreaterThanEqual | :white_check_mark: |Control Flow
Expand
|OpCode| Status | |--|--| | OpPhi | :red_circle: | | OpLoopMerge | :white_check_mark: | | OpSelectionMerge | :white_check_mark: | | OpLabel |:white_check_mark: | | OpBranch | :white_check_mark: | | OpBranchConditional | :white_check_mark: | | OpSwitch | :red_circle: | | OpReturn | :red_circle: | | OpReturnValue | :red_circle: |Contributing
Encountered a bug? Have an idea for a new feature? This project is open to all
sorts of contribution! Feel free to head to the Issues tab and describe your
request!
Authors
License
This project is licensed under the Apache 2.0 license.
Owner
- Name: Rayan Hatout
- Login: rayanht
- Kind: user
- Location: London, United Kingdom
- Website: https://rayanht.xyz
- Twitter: rayanhtt
- Repositories: 53
- Profile: https://github.com/rayanht
ML Engineer @ Meta
Citation (CITATION.cff)
cff-version: 1.2.0 message: "If you use this software, please cite it as below." authors: - family-names: "Hatout" given-names: "Rayan" orcid: "https://orcid.org/0000-0001-6240-1473" title: "SPIRVSmith" version: v1.7.0 doi: 10.5281/zenodo.6466654 date-released: 2022-04-19 url: "https://github.com/rayanht/SPIRVSmith"
GitHub Events
Total
- Watch event: 1
Last Year
- Watch event: 1
Dependencies
- autoflake 1.4 develop
- black 22.3.0 develop
- cfgv 3.3.1 develop
- click 8.1.3 develop
- coverage 6.4.1 develop
- cycler 0.11.0 develop
- distlib 0.3.4 develop
- filelock 3.7.1 develop
- flake8 4.0.1 develop
- fonttools 4.33.3 develop
- identify 2.5.1 develop
- kiwisolver 1.4.2 develop
- matplotlib 3.5.2 develop
- mccabe 0.6.1 develop
- mypy 0.950 develop
- mypy-extensions 0.4.3 develop
- nodeenv 1.6.0 develop
- pathspec 0.9.0 develop
- pillow 9.1.1 develop
- platformdirs 2.5.2 develop
- pre-commit 2.19.0 develop
- pycodestyle 2.8.0 develop
- pyflakes 2.4.0 develop
- pytest-flakefinder 1.0.0 develop
- seaborn 0.11.2 develop
- setuptools-scm 6.4.2 develop
- toml 0.10.2 develop
- virtualenv 20.14.1 develop
- antlr4-python3-runtime 4.9.3
- anyio 3.6.1
- atomicwrites 1.4.0
- attrs 21.4.0
- certifi 2022.5.18.1
- charset-normalizer 2.0.12
- colorama 0.4.4
- daiquiri 3.0.1
- dataclass-wizard 0.22.1
- datadog 0.44.0
- ddsketch 2.0.3
- ddtrace 1.1.4
- dill 0.3.5.1
- frozendict 2.3.2
- gitdb 4.0.9
- gitpython 3.1.27
- gputil 1.4.0
- h11 0.12.0
- httpcore 0.14.7
- httpx 0.22.0
- hydra-core 1.2.0
- idna 3.3
- iniconfig 1.1.1
- numpy 1.22.4
- omegaconf 2.2.2
- packaging 21.3
- pandas 1.4.2
- pluggy 1.0.0
- protobuf 3.20.1
- py 1.11.0
- py-cpuinfo 8.0.0
- pydantic 1.9.1
- pyparsing 3.0.9
- pytest 7.1.2
- python-dateutil 2.8.2
- python-json-logger 2.0.2
- pytz 2022.1
- pyyaml 6.0
- requests 2.28.0
- rfc3986 1.5.0
- scipy 1.8.1
- shortuuid 1.0.9
- six 1.16.0
- smmap 5.0.0
- sniffio 1.2.0
- spirv-enums 1.0
- spirvsmith-server-client 0.2.0
- tenacity 8.0.1
- tomli 2.0.1
- tqdm 4.64.0
- typing-extensions 4.2.0
- ulid-py 1.1.0
- urllib3 1.26.9
- vulkan-platform-py 0.4.1
- autoflake ^1.4 develop
- black ^22.3 develop
- coverage ^6.3.2 develop
- flake8 ^4.0.1 develop
- mypy ^0.950 develop
- pre-commit ^2.18.1 develop
- pytest-flakefinder ^1.0.0 develop
- seaborn ^0.11.2 develop
- tqdm ^4.64.0 develop
- GitPython ^3.1.27
- daiquiri ^3.0.1
- dataclass-wizard ^0.22.1
- datadog ^0.44.0
- ddtrace ^1.0.1
- frozendict ^2.3.2
- hydra-core ^1.1.1
- numpy ^1.22.4
- pandas ^1.4.2
- pydantic ^1.9.1
- pytest ^7.1.1
- python >=3.10,<3.11
- scipy ^1.8.1
- shortuuid ^1.0.8
- spirv-enums ^1.0
- spirvsmith-server-client ^0.2.0
- tqdm ^4.64.0
- ulid-py ^1.1
- vulkan-platform-py ^0.4.1
- abatilo/actions-poetry v2.0.0 composite
- actions/checkout v3 composite
- actions/setup-python v3 composite
- fossas/fossa-action v1.1.0 composite
- paambaati/codeclimate-action v2.7.5 composite
- python 3.10-slim build