github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/imports/wasi_snapshot_preview1/random.go (about)

     1  package wasi_snapshot_preview1
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  
     7  	"github.com/tetratelabs/wazero/api"
     8  	"github.com/tetratelabs/wazero/experimental/sys"
     9  	"github.com/tetratelabs/wazero/internal/wasip1"
    10  	"github.com/tetratelabs/wazero/internal/wasm"
    11  )
    12  
    13  // randomGet is the WASI function named RandomGetName which writes random
    14  // data to a buffer.
    15  //
    16  // # Parameters
    17  //
    18  //   - buf: api.Memory offset to write random values
    19  //   - bufLen: size of random data in bytes
    20  //
    21  // Result (Errno)
    22  //
    23  // The return value is ErrnoSuccess except the following error conditions:
    24  //   - sys.EFAULT: `buf` or `bufLen` point to an offset out of memory
    25  //   - sys.EIO: a file system error
    26  //
    27  // For example, if underlying random source was seeded like
    28  // `rand.NewSource(42)`, we expect api.Memory to contain:
    29  //
    30  //	                   bufLen (5)
    31  //	          +--------------------------+
    32  //	          |                        	 |
    33  //	[]byte{?, 0x53, 0x8c, 0x7f, 0x96, 0xb1, ?}
    34  //	    buf --^
    35  //
    36  // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
    37  var randomGet = newHostFunc(wasip1.RandomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
    38  
    39  func randomGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
    40  	sysCtx := mod.(*wasm.ModuleInstance).Sys
    41  	randSource := sysCtx.RandSource()
    42  	buf, bufLen := uint32(params[0]), uint32(params[1])
    43  
    44  	randomBytes, ok := mod.Memory().Read(buf, bufLen)
    45  	if !ok { // out-of-range
    46  		return sys.EFAULT
    47  	}
    48  
    49  	// We can ignore the returned n as it only != byteCount on error
    50  	if _, err := io.ReadAtLeast(randSource, randomBytes, int(bufLen)); err != nil {
    51  		return sys.EIO
    52  	}
    53  
    54  	return 0
    55  }