I'm writing some inner-loop type input parsing code, and need to compare the length of a buffer to a uint32
. The ideal solution would be fast, concise, dumb (easy to see the correctness of), and work for all possible inputs including those in which an attacker maliciously manipulates the values. Integer overflow is a big deal in this context if it can be exploited to crash the program. This is what I have so far:
// Safely check if len(buf) <= size for all possible values of each
func sizeok(buf []MyType, size uint32) bool {
var n int = len(buf)
return n == int(uint32(n)) && uint32(n) <= size
}
That's a pain, and can't be abstracted over other slice types.
My questions: First, is this actually correct? (You can never be too careful defending against exploitable integer overflows.) Second, is there a simpler way to do it with a single comparison? Maybe uint(len(buf)) <= uint(size)
if that could be guaranteed to work securely on all platforms and inputs? Or uint64(len(buf)) <= uint64(size)
if that won't generate suboptimal code on 32-bit platforms?
The Go Programming Language Specification
The built-in functions len and cap take arguments of various types and return a result of type int. The implementation guarantees that the result always fits into an int.
Call Argument type Result len(s) string type string length in bytes [n]T, *[n]T array length (== n) []T slice length map[K]T map length (number of defined keys) chan T number of elements queued in channel buffer
uint32 all unsigned 32-bit integers (0 to 4294967295) int64 all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
There is also a set of predeclared numeric types with implementation-specific sizes:
uint either 32 or 64 bits int same size as uint
len(buf)
is type int
which is 32 or 64 bits depending on the implementation. For example, for any Go type with a built-in len
function,
// Safely check if len(buf) <= size for all possible values of each
var size uint32
if int64(len(buf)) <= int64(size) {
// handle len(buf) <= size
}