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
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 and the idea. Thank you guy.
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.