Source File
io.go
Belonging Package
internal/saferio
// Copyright 2022 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package saferio provides I/O functions that avoid allocating large// amounts of memory unnecessarily. This is intended for packages that// read data from an [io.Reader] where the size is part of the input// data but the input may be corrupt, or may be provided by an// untrustworthy attacker.package saferioimport ()// chunk is an arbitrary limit on how much memory we are willing// to allocate without concern.const chunk = 10 << 20 // 10M// ReadData reads n bytes from the input stream, but avoids allocating// all n bytes if n is large. This avoids crashing the program by// allocating all n bytes in cases where n is incorrect.//// The error is io.EOF only if no bytes were read.// If an io.EOF happens after reading some but not all the bytes,// ReadData returns io.ErrUnexpectedEOF.func ( io.Reader, uint64) ([]byte, error) {if int64() < 0 || != uint64(int()) {// n is too large to fit in int, so we can't allocate// a buffer large enough. Treat this as a read failure.return nil, io.ErrUnexpectedEOF}if < chunk {:= make([]byte, ), := io.ReadFull(, )if != nil {return nil,}return , nil}var []byte:= make([]byte, chunk)for > 0 {:=if > chunk {= chunk}, := io.ReadFull(, [:])if != nil {if len() > 0 && == io.EOF {= io.ErrUnexpectedEOF}return nil,}= append(, [:]...)-=}return , nil}// ReadDataAt reads n bytes from the input stream at off, but avoids// allocating all n bytes if n is large. This avoids crashing the program// by allocating all n bytes in cases where n is incorrect.func ( io.ReaderAt, uint64, int64) ([]byte, error) {if int64() < 0 || != uint64(int()) {// n is too large to fit in int, so we can't allocate// a buffer large enough. Treat this as a read failure.return nil, io.ErrUnexpectedEOF}if < chunk {:= make([]byte, ), := .ReadAt(, )if != nil {// io.SectionReader can return EOF for n == 0,// but for our purposes that is a success.if != io.EOF || > 0 {return nil,}}return , nil}var []byte:= make([]byte, chunk)for > 0 {:=if > chunk {= chunk}, := .ReadAt([:], )if != nil {return nil,}= append(, [:]...)-=+= int64()}return , nil}// SliceCapWithSize returns the capacity to use when allocating a slice.// After the slice is allocated with the capacity, it should be// built using append. This will avoid allocating too much memory// if the capacity is large and incorrect.//// A negative result means that the value is always too big.func (, uint64) int {if int64() < 0 || != uint64(int()) {return -1}if > 0 && > (1<<64-1)/ {return -1}if * > chunk {= chunk /if == 0 {= 1}}return int()}// SliceCap is like SliceCapWithSize but using generics.func [ any]( uint64) int {var:= uint64(unsafe.Sizeof())return SliceCapWithSize(, )}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)