I worked on my first open-source package last weekend.
ccoVeille / go-safecast
Safe number conversion in Go: address gosec G115 and cwe-190 Integer Overflow or Wraparound
🪄 go-safecast: safe numbers conversion
go-safecast solves the type conversion issues in Go
In Go, integer type conversion can lead to a silent and unexpected behavior and errors if not handled carefully.
This package helps to convert any number to another, and report an error when if there would be a loss or overflow in the conversion
Usage
package main import ( "fmt" "math" "github.com/ccoveille/go-safecast" ) func main() { var a int a = 42 b, err := safecast.ToUint8(a) // everything is fine if err != nil { fmt.Println(err) } fmt.Println(b) // Output: 42 a = 255 + 1 _, err = safecast.ToUint8(a) // 256 is greater than uint8 maximum value if err != nil { fmt.Println(err) // Output: conversion issue: 256
…About the story behind this library, you can read my first article about integer overflow in Go

About the gosec G115 drama, or how I faced back integer conversion overflow in Go 🤯
Christophe Colombier ・ Sep 9 '24
As I found nothing to cope with this kind of error, except adding a lot of boilerplate for each cast to do, so I decided to make my own Go package.
@ldemailly helped me to review the code, thank.
The package is now mature enough for me to talk about it.
So instead of this
var a int var b uint8 a = 255 + 1 b = uint8(a) if a < 0 || a > math.MaxUint8 { log.Println("overflow") } fmt.Println(b) a = -1 b = uint8(a) if a < 0 || a > math.MaxUint8 { log.Println("overflow") } fmt.Println(b) c, d := 255, 300 res := max(c, d) if res < 0 || res > math.MaxInt8 { log.Println("overflow") } fmt.Println(int8(res)) str := "\x99" // hexadecimal representation of Trademark ASCII character: â„¢ e := str[0] if e < 0 || e > math.MaxInt8 { log.Println("overflow") } fmt.Println(int8(e))
You can now do this
var a int var b uint8 a = 255 + 1 b, err := safecast.ToUint8(a) if err != nil { log.Println(err) } fmt.Println(b) a = -1 b, err = safecast.ToUint8(a) if err != nil { log.Println(err) } fmt.Println(b) c, d := 255, 300 res := max(c, d) g, err := safecast.ToInt8(res) if err != nil { log.Println(err) } fmt.Println(g) str := "\x99" // hexadecimal representation of Trademark ASCII character: â„¢ e := str[0] f, err := safecast.ToUint8(e) if err != nil { log.Println(err) } fmt.Println(f)
I'm curious about your feedbacks
Top comments (1)
Great series on a serious problem, and thanks for the mention!
If you don’t mind I’d like to offer my smaller and simpler (I think) generic version: pkg.go.dev/fortio.org/safecast for people to consider. It also has Must* variant of the conversions.