Giter Club home page Giter Club logo

gcassert's Introduction

gcassert

gcassert is a program for making assertions about compiler decisions in Go programs, via inline comment directives like //gcassert:inline.

Currently supported directives:

  • //gcassert:inline to assert function callsites are inlined
  • //gcassert:bce to assert bounds checks are eliminated
  • //gcassert:noescape to assert variables don't escape to the heap

Example

Given a file foo.go:

package foo

func addOne(i int) int {
    return i+1
}

//gcassert:inline
func addTwo(i int) int {
    return i+1
}

func a(ints []int) int {
    var sum int
    for i := range ints {
        //gcassert:bce,inline
        sum += addOne(ints[i])

        sum += addTwo(ints[i]) //gcassert:bce

        sum += ints[i] //gcassert:bce
    }
    return sum
}

The inline //gcassert directive will cause gcassert to fail if the line sum += addOne(ints[i]) is either not inlined or contains bounds checks.

A //gcassert:inline directive on a function will cause gcassert to fail if any of the callers of that function do not get inlined.

//gcassert comments expect a comma-separated list of directives after //gcassert:. They can be included above the line in question or after, as an inline comment.

Installation

To get the gcassert binary:

go get github.com/jordanlewis/gcassert/cmd/gcassert

To get the gcassert library:

go get github.com/jordanlewis/gcassert

Usage

As a binary

Run gcassert on packages containing gcassert directives, like this:

gcassert ./package/path

The program will output all lines that had a gcassert directive that wasn't respected by the compiler.

For example, running on the testdata directory in this library will produce the following output:

$ gcassert ./testdata
testdata/noescape.go:21:        foo := foo{a: 1, b: 2}: foo escapes to heap:
testdata/bce.go:8:      fmt.Println(ints[5]): Found IsInBounds
testdata/bce.go:17:     sum += notInlinable(ints[i]): call was not inlined
testdata/bce.go:19:     sum += notInlinable(ints[i]): call was not inlined
testdata/inline.go:45:  alwaysInlined(3): call was not inlined
testdata/inline.go:51:  sum += notInlinable(i): call was not inlined
testdata/inline.go:55:  sum += 1: call was not inlined
testdata/inline.go:58:  test(0).neverInlinedMethod(10): call was not inlined

Inspecting each of the listed lines will show a //gcassert directive that wasn't upheld when running the compiler on the package.

As a library

gcassert is runnable as a library as well, for integration into your linter suite. It has a single package function, gcassert.GCAssert.

To use it, pass in an io.Writer to which errors will be written and a list of paths to check for gcassert assertions, like this:

package main

import "github.com/jordanlewis/gcassert"

func main() {
    var buf strings.Builder
    if err := gcassert.GCAssert(&buf, "./path/to/package", "./otherpath/to/package"); err != nil {
        // handle non-lint-failure related errors
        panic(err)
    }
    // Output the errors to stdout.
    fmt.Println(buf.String())
}

Directives

//gcassert:inline

The inline directive on a CallExpr asserts that the following statement contains a function that is inlined by the compiler. If the function does not get inlined, gcassert will fail.

The inline directive on a FuncDecl asserts that every caller of that function is actually inlined by the compiler.

//gcassert:bce

The bce directive asserts that the following statement contains a slice index that has no necessary bounds checks. If the compiler adds bounds checks, gcassert will fail.

//gcassert:noescape

The noescape directive asserts that the line it's attached to (meaning, whichever Go AST node is annotated by the comment) produces no "escaped to heap" messages by the Go compiler.

The Go compiler emits an "escaped to heap" message for a particular line of code if any variables on that line of code are forced to escape.

Typically, the compiler will emit such a message on the line of code that the variable is declared on. This includes method receivers, method arguments, and var declarations.

This means that the annotation must be attached to the line of code that actually contains the variable in question. For a multi-line function signature, for example, the annotation must come on the line that has the variable that would be expected not to escape to the heap:

type foo struct { a int }

// This annotation will pass, because f does not escape.
//gcassert:noescape
func (f foo) returnA(
// This annotation will fail, because a will escape to the heap.
//gcassert:noescape
    a int,
) *int {
    return &a
}

gcassert's People

Contributors

jordanlewis avatar yuzefovich avatar kocoten1992 avatar erikgrinaker avatar srosenberg avatar

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.