Giter Club home page Giter Club logo

spirvsmith's Introduction

SPIRVSmith

GitHub Workflow Status GitHub Test Coverage Maintainability FOSSA Status Code style: black DOI

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:

Table of Contents

Installation

SPIRVSmith uses poetry to manage Python dependencies and ships with scripts to install external dependencies.

  1. Follow the poetry installation instructions for your platform.

  2. Grab a local copy of SPIRVSmith:

$ git clone https://github.com/rayanht/SPIRVSmith.git && cd SPIRVSmith
  1. Install Python dependencies using poetry and start a poetry shell:
$ poetry install && poetry shell
  1. Install the external dependencies:
$ mkdir bin
$ sh scripts/get_spirv_tools.sh <platform>

Replace <platform> by either linux or macos (No support for Windows ๐Ÿ˜ญ)

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:

$ 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

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

// [ 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

Miscellanous

Expand
OpCode Status
OpNop ๐Ÿ”ด
OpUndef ๐Ÿ”ด
OpSizeOf ๐Ÿ”ด

Debug

Expand
OpCode Status
OpSourceContinued ๐Ÿ”ด
OpSource ๐Ÿ”ด
OpSourceExtension ๐Ÿ”ด
OpName ๐Ÿ”ด
OpMemberName ๐Ÿ”ด
OpString ๐Ÿ”ด
OpLine ๐Ÿ”ด
OpNoLine ๐Ÿ”ด
OpModuleProcessed ๐Ÿ”ด

Annotation

Expand
OpCode Status
OpDecorate โœ…
OpMemberDecorate โœ…
OpDecorationGroup ๐Ÿ”ด
OpGroupDecorate ๐Ÿ”ด
OpGroupMemberDecorate ๐Ÿ”ด
OpDecorateId ๐Ÿ”ด
OpDecorateString ๐Ÿ”ด
OpMemberDecorateString ๐Ÿ”ด

Extension

Expand
OpCode Status
OpExtension โœ…
OpExtInstImport โœ…
OpExtInst โœ…

Mode-Setting

Expand
OpCode Status
OpMemoryModel โœ…
OpEntryPoint โœ…
OpExecutionMode โœ…
OpCapability โœ…
OpExecutionModeId ๐Ÿ”ด

Type-Declaration

Expand
OpCode Status
OpTypeVoid โœ…
OpTypeBool โœ…
OpTypeInt โœ…
OpTypeFloat โœ…
OpTypeVector โœ…
OpTypeMatrix โœ…
OpTypeImage ๐Ÿ”ด
OpTypeSampler ๐Ÿ”ด
OpTypeSampledImage ๐Ÿ”ด
OpTypeArray โœ…
OpTypeRuntimeArray ๐Ÿ”ด
OpTypeStruct โœ…
OpTypeOpaque ๐Ÿ”ด
OpTypePointer โœ…
OpTypeFunction โœ…

Constant-Creation

Expand
OpCode Status
OpConstantTrue โœ…
OpConstantFalse โœ…
OpConstant โœ…
OpConstantComposite โœ…
OpConstantSampler ๐Ÿ”ด
OpConstantNull ๐Ÿ”ด
OpSpecConstantTrue ๐Ÿ”ด
OpSpecConstantFalse ๐Ÿ”ด
OpSpecConstant ๐Ÿ”ด
OpSpecConstantComposite ๐Ÿ”ด
OpSpecConstantOp ๐Ÿ”ด

Memory

Expand
OpCode Status
OpVariable โœ…
OpImageTexelPointer ๐Ÿ”ด
OpLoad โœ…
OpStore โœ…
OpCopyMemory ๐Ÿ”ด
OpCopyMemorySized ๐Ÿ”ด
OpAccessChain โœ…
OpInBoundsAccessChain ๐Ÿ”ด
OpPtrAccessChain ๐Ÿ”ด
OpPtrEqual ๐Ÿ”ด
OpPtrNotEqual ๐Ÿ”ด
OpPtrDiff ๐Ÿ”ด

Function

Expand
OpCode Status
OpFunction โœ…
OpFunctionParameter โœ…
OpFunctionEnd โœ…
OpFunctionCall ๐Ÿ”ด

Image

Expand
OpCode Status
OpSampledImage ๐Ÿ”ด
OpImageSampleImplicitLod ๐Ÿ”ด
OpImageSampleExplicitLod ๐Ÿ”ด
OpImageSampleDrefImplicitLod ๐Ÿ”ด
OpImageSampleDrefExplicitLod ๐Ÿ”ด
OpImageSampleProjImplicitLod ๐Ÿ”ด
OpImageSampleProjExplicitLod ๐Ÿ”ด
OpImageSampleProjDrefImplicitLod ๐Ÿ”ด
OpImageSampleProjDrefExplicitLod ๐Ÿ”ด
OpImageFetch ๐Ÿ”ด
OpImageGather ๐Ÿ”ด
OpImageDrefGather ๐Ÿ”ด
OpImageRead ๐Ÿ”ด
OpImageWrite ๐Ÿ”ด
OpImage ๐Ÿ”ด
OpImageQueryFormat ๐Ÿ”ด
OpImageQueryOrder ๐Ÿ”ด
OpImageQuerySizeLod ๐Ÿ”ด
OpImageQuerySize ๐Ÿ”ด
OpImageQueryLod ๐Ÿ”ด
OpImageQueryLevels ๐Ÿ”ด
OpImageQuerySamples ๐Ÿ”ด
OpImageSparseSampleImplicitLod ๐Ÿ”ด
OpImageSparseSampleExplicitLod ๐Ÿ”ด
OpImageSparseSampleDrefImplicitLod ๐Ÿ”ด
OpImageSparseSampleDrefExplicitLod ๐Ÿ”ด
OpImageSparseFetch ๐Ÿ”ด
OpImageSparseGather ๐Ÿ”ด
OpImageSparseDrefGather ๐Ÿ”ด
OpImageSparseTexelsResident ๐Ÿ”ด
OpImageSparseRead ๐Ÿ”ด

Conversion

Expand
OpCode Status
OpConvertFToU โœ…
OpConvertFToS โœ…
OpConvertSToF โœ…
OpConvertUToF โœ…
OpUConvert ๐Ÿ”ด
OpSConvert ๐Ÿ”ด
OpFConvert ๐Ÿ”ด
OpQuantizeToF16 ๐Ÿ”ด
OpConvertPtrToU ๐Ÿ”ด
OpSatConvertSToU ๐Ÿ”ด
OpSatConvertUToS ๐Ÿ”ด
OpConvertUToPtr ๐Ÿ”ด
OpPtrCastToGeneric ๐Ÿ”ด
OpGenericCastToPtr ๐Ÿ”ด
OpGenericCastToPtrExplicit ๐Ÿ”ด
OpBitcast ๐Ÿ”ด

Composite

Expand
OpCode Status
OpVectorExtractDynamic โœ…
OpVectorInsertDynamic โœ…
OpVectorShuffle โœ…
OpCompositeConstruct ๐Ÿ”ด
OpCompositeExtract โœ…
OpCompositeInsert โœ…
OpCopyObject โœ…
OpTranspose โœ…
OpCopyLogical ๐Ÿ”ด

Arithmetic

Expand
OpCode Status
OpSNegate โœ…
OpFNegate โœ…
OpIAdd โœ…
OpFAdd โœ…
OpISub โœ…
OpFSub โœ…
OpIMul โœ…
OpFMul โœ…
OpUDiv โœ…
OpSDiv โœ…
OpFDiv โœ…
OpUMod โœ…
OpSRem โœ…
OpSMod โœ…
OpFRem โœ…
OpFMod โœ…
OpVectorTimesScalar โœ…
OpMatrixTimesScalar โœ…
OpVectorTimesMatrix โœ…
OpMatrixTimesVector โœ…
OpMatrixTimesMatrix โœ…
OpOuterProduct โœ…
OpDot โœ…
OpIAddCarry ๐Ÿ”ด
OpISubBorrow ๐Ÿ”ด
OpUMulExtended ๐Ÿ”ด
OpSMulExtended ๐Ÿ”ด

Bit

Expand
OpCode Status
OpShiftRightLogical โœ…
OpShiftRightArithmetic โœ…
OpShiftLeftLogical โœ…
OpBitwiseOr โœ…
OpBitwiseXor โœ…
OpBitwiseAnd โœ…
OpNot โœ…
OpBitFieldInsert โœ…
OpBitFieldSExtract โœ…
OpBitFieldUExtract โœ…
OpBitReverse โœ…
OpBitCount โœ…

Relational and Logical

Expand
OpCode Status
OpAny โœ…
OpAll โœ…
OpIsNan โœ…
OpIsInf โœ…
OpIsFinite ๐Ÿ”ด
OpIsNormal ๐Ÿ”ด
OpSignBitSet ๐Ÿ”ด
OpOrdered ๐Ÿ”ด
OpUnordered ๐Ÿ”ด
OpLogicalEqual โœ…
OpLogicalNotEqual โœ…
OpLogicalOr โœ…
OpLogicalAnd โœ…
OpLogicalNot โœ…
OpSelect โœ…
OpIEqual โœ…
OpINotEqual โœ…
OpUGreaterThan โœ…
OpSGreaterThan โœ…
OpUGreaterThanEqual โœ…
OpSGreaterThanEqual โœ…
OpULessThan โœ…
OpSLessThan โœ…
OpULessThanEqual โœ…
OpSLessThanEqual โœ…
OpFOrdEqual โœ…
OpFUnordEqual โœ…
OpFOrdNotEqual โœ…
OpFUnordNotEqual โœ…
OpFOrdLessThan โœ…
OpFUnordLessThan โœ…
OpFOrdGreaterThan โœ…
OpFUnordGreaterThan โœ…
OpFOrdLessThanEqual โœ…
OpFUnordLessThanEqual โœ…
OpFOrdGreaterThanEqual โœ…
OpFUnordGreaterThanEqual โœ…

Control Flow

Expand
OpCode Status
OpPhi ๐Ÿ”ด
OpLoopMerge โœ…
OpSelectionMerge โœ…
OpLabel โœ…
OpBranch โœ…
OpBranchConditional โœ…
OpSwitch ๐Ÿ”ด
OpReturn ๐Ÿ”ด
OpReturnValue ๐Ÿ”ด

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.

FOSSA Status

spirvsmith's People

Contributors

rayanht avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

fossabot simrit1

spirvsmith's Issues

SPIRVSmith occasionally generates forward references

Describe the bug
SPIRVSmith sometimes generates decorations for instructions that seemingly do not exist. This creates forward references which in turn fail the SPIR-V validator stage.

To Reproduce
N/A

Expected behavior
No forward references should be generated.

Artifacts (Amber file, SPIR-V assembly file...)
Refer to the following generated shaders:

  • 86nykCkbnQbbAkMZQL5XQz
  • iT4bBEigfyskHRTuHpXyU2
  • LFQVWfcJk6N3GDts93JZko
  • UvM8NCmCGLU9dvWu5njd2R

Additional context
This doesn't happen too often (~10% incidence rate according to logs) but it's a very low-hanging fruit to increase our generation throughput.

image

System-wide spirv executables used instead of the ones installed from scripts

Heya,

I was trying to run this on my computer and I am unsure if I need to install the spirv dependencies through the provided scripts or using my packet manager. It seems like some of the spirv executable files are picked from the system and some others from the installation script location. I am unsure if that is an intended behavior.

It also seems that the designated location for the install script (bin/) does not match the location in which the executable files are installed (bin/installed/bin)

System-wide:

def assemble_spasm_file(infile_path: str, outfile_path: str) -> SubprocessResult:
process: subprocess.CompletedProcess = subprocess.run(
[
"spirv-as",
"--target-env",
TARGET_SPIRV_VERSION,
infile_path,
"-o",
outfile_path,
],

def disassemble_spv_file(spv_path: str, outfile_path: str, silent: bool = False):
process: subprocess.CompletedProcess = subprocess.run(
[
"spirv-dis",
"--no-indent",
"--raw-id",
"-o",
outfile_path,
spv_path,
],

def validate_spv_file(
filename: str,
) -> SubprocessResult:
process: subprocess.CompletedProcess = subprocess.run(
[
"spirv-val",
"--target-env",
TARGET_SPIRV_VERSION,
filename,
],

Dependency configuration:

def optimise_spv_file(shader: SPIRVShader, filename: str) -> bool:
process: subprocess.CompletedProcess = subprocess.run(
[
shader.context.config.binaries.OPTIMISER_PATH,
f"--target-env={TARGET_SPIRV_VERSION}",
filename,
"-o",
f"out/{shader.id}/spv_opt/shader.spv",
],

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.