GithubHelp home page GithubHelp logo

charithe / durationcheck Goto Github PK

View Code? Open in Web Editor NEW
46.0 5.0 6.0 34 KB

Go linter to detect erroneous multiplication of duration values

License: Apache License 2.0

Makefile 3.26% Go 96.74%
go golang linter govet

durationcheck's Introduction

CircleCI

Duration Check

A Go linter to detect cases where two time.Duration values are being multiplied in possibly erroneous ways.

Consider the following (highly contrived) code:

func waitForSeconds(someDuration time.Duration) {
	timeToWait := someDuration * time.Second
	fmt.Printf("Waiting for %s\n", timeToWait)
}

func main() {
	waitForSeconds(5) // waits for 5 seconds
	waitForSeconds(5 * time.Second) // waits for 1388888h 53m 20s
}

Both invocations of the function are syntactically correct but the second one is probably not what most people want. In this contrived example it is quite easy to spot the mistake. However, if the incorrect waitForSeconds invocation is nested deep within a complex piece of code that runs in the background, the mistake could go unnoticed for months (which is exactly what happened in a production backend system of fairly well-known software service).

See the test cases for more examples of the types of errors detected by the linter.

Installation

Requires Go 1.14 or above.

go get -u github.com/charithe/durationcheck/cmd/durationcheck

Usage

Invoke durationcheck with your package name

durationcheck ./...
# or
durationcheck github.com/you/yourproject/...

durationcheck's People

Contributors

alexandear avatar bunyk avatar charithe avatar ldez avatar sylvia7788 avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar

durationcheck's Issues

False positive when multiplying against an untyped int constant, again

I picked up this linter in the latest golangci-lint release (includes 0.0.3) and am trying with the latest 0.0.4 version as well. I am still seeing the previously-resolved false positive. The only difference I can think of might be because my constant is in a different package?

package session:

const TokenExp = 10 * 60

package service (test file):

require.WithinDuration(t, time.Now().Add(session.TokenExp*time.Second), loginResp.ExpiresAt.AsTime(),
2*time.Second)

Result:

$ durationcheck ./...
.../session_test.go:54:4: Multiplication of durations: `session.TokenExp * time.Second`

How to calculate duration without violating durationcheck?

A common requirement is to read a value from some where and use it to compose a duration, for example, read from json to get a value as seconds and save to a variable:

s := gjson.Get(js, "duration").Int()

usually we create a duration by multiply time.Second:

du := time.Second * time.Duration(s)

But this will trigger a durationcheck failure.

I understand why durationcheck is required, but I'm confused what's the elegant way to process this problem because a direct multiply from int to time.Duration is not allowed, would you give an example to show the me the solution?

False positive when multiplying with int type struct field

Struct fields are not taken into account when assessing duration multiplication. Consider a struct that has int field. When this field is multiplied by a valid duration value, linter throws an error (to multiply with duration, the field needs to be converted to time.Duration first).

See this example:

package main

import (
	"time"
)

type s struct {
	d int
}

func main() {
	ss := s{10}
	_ = time.Duration(ss.d) * time.Second
}

Another false positive

	daysInWeekend := 2
	weekendDuration := time.Duration(daysInWeekend) * 24 * time.Hour // durationcheck complains
	weekendDuration2 := time.Duration(daysInWeekend*24) * time.Hour // fine for durationcheck

weekendDuration, and weekendDuration2 both contain the correct duration of 48h.

False positive caused by brackets

time.Duration(attempts) * time.Millisecond is fine, but
time.Duration((attempts)) * time.Millisecond causes a false positive.

(The real scenario was doing some maths inside the time.Duration(): time.Duration((attempts-1)*2)*time.Millisecond).)

false-positive with int pointer dereference

type myStruct struct {
	fieldC *int
}

func bug() {
	ms := myStruct{fieldC: func(v int) *int { return &v }(10)}

	_ = time.Duration(*somePointerDurationMillis()) * time.Millisecond

	_ = time.Millisecond * time.Duration(*somePointerDurationMillis())

	_ = time.Duration(*ms.fieldC) * time.Second

	_ = time.Second * time.Duration(*ms.fieldC)
}

func somePointerDurationMillis() *int {
	v := 10
	return &v
}
Multiplication of durations: `time.Duration(*somePointerDurationMillis()) * time.Millisecond`
Multiplication of durations: `time.Millisecond * time.Duration(*somePointerDurationMillis())`
Multiplication of durations: `time.Duration(*ms.fieldC) * time.Second`
Multiplication of durations: `time.Second * time.Duration(*ms.fieldC)`

Why is the code in Readme wrong?

Can I ask you why the code in Readme is wrong?

func waitFor(someDuration time.Duration) {
    timeToWait := someDuration * time.Second
    time.Sleep(timeToWait)
}

Please clarify example

Hello!

A caller would reasonably expect waitFor(5 * time.Seconds) to wait for ~5 seconds 
but they would actually end up waiting for ~1,388,889 hours.

Where did these numbers come from?
The function will sleep 5 seconds as expected:
https://goplay.tools/snippet/izCeDb5NL9W

Are you talking about some tricky runtime feature?
Or do you mean that I can pass not 5, but a larger number? Why did it turn out 1,388,889 hours exactly?
Or what are we talking about?

Thanks!

False positive when multiplying against a negative duration

Sample code

package dur

import "time"

const _ = -time.Hour * time.Duration(1)

const _ = time.Hour * -time.Duration(1)

const _ = -(time.Hour * time.Duration(1))

Output

Multiplication of durations: `time.Hour * -time.Duration(1)` (durationcheck)
const _ = time.Hour * -time.Duration(1)
          ^

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.