1 package sys
2
3 import (
4 "errors"
5 "fmt"
6 "io"
7 "net"
8 "time"
9
10 experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
11 "github.com/tetratelabs/wazero/internal/platform"
12 "github.com/tetratelabs/wazero/sys"
13 )
14
15
16
17 type Context struct {
18 args, environ [][]byte
19 argsSize, environSize uint32
20
21 walltime sys.Walltime
22 walltimeResolution sys.ClockResolution
23 nanotime sys.Nanotime
24 nanotimeResolution sys.ClockResolution
25 nanosleep sys.Nanosleep
26 osyield sys.Osyield
27 randSource io.Reader
28 fsc FSContext
29 }
30
31
32
33
34
35 func (c *Context) Args() [][]byte {
36 return c.args
37 }
38
39
40
41
42
43
44 func (c *Context) ArgsSize() uint32 {
45 return c.argsSize
46 }
47
48
49
50
51
52 func (c *Context) Environ() [][]byte {
53 return c.environ
54 }
55
56
57
58
59
60
61 func (c *Context) EnvironSize() uint32 {
62 return c.environSize
63 }
64
65
66 func (c *Context) Walltime() (sec int64, nsec int32) {
67 return c.walltime()
68 }
69
70
71 func (c *Context) WalltimeNanos() int64 {
72 sec, nsec := c.Walltime()
73 return (sec * time.Second.Nanoseconds()) + int64(nsec)
74 }
75
76
77 func (c *Context) WalltimeResolution() sys.ClockResolution {
78 return c.walltimeResolution
79 }
80
81
82 func (c *Context) Nanotime() int64 {
83 return c.nanotime()
84 }
85
86
87 func (c *Context) NanotimeResolution() sys.ClockResolution {
88 return c.nanotimeResolution
89 }
90
91
92 func (c *Context) Nanosleep(ns int64) {
93 c.nanosleep(ns)
94 }
95
96
97 func (c *Context) Osyield() {
98 c.osyield()
99 }
100
101
102 func (c *Context) FS() *FSContext {
103 return &c.fsc
104 }
105
106
107
108 func (c *Context) RandSource() io.Reader {
109 return c.randSource
110 }
111
112
113
114
115
116 func DefaultContext(fs experimentalsys.FS) *Context {
117 if sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []experimentalsys.FS{fs}, []string{""}, nil); err != nil {
118 panic(fmt.Errorf("BUG: DefaultContext should never error: %w", err))
119 } else {
120 return sysCtx
121 }
122 }
123
124
125
126 func NewContext(
127 max uint32,
128 args, environ [][]byte,
129 stdin io.Reader,
130 stdout, stderr io.Writer,
131 randSource io.Reader,
132 walltime sys.Walltime,
133 walltimeResolution sys.ClockResolution,
134 nanotime sys.Nanotime,
135 nanotimeResolution sys.ClockResolution,
136 nanosleep sys.Nanosleep,
137 osyield sys.Osyield,
138 fs []experimentalsys.FS, guestPaths []string,
139 tcpListeners []*net.TCPListener,
140 ) (sysCtx *Context, err error) {
141 sysCtx = &Context{args: args, environ: environ}
142
143 if sysCtx.argsSize, err = nullTerminatedByteCount(max, args); err != nil {
144 return nil, fmt.Errorf("args invalid: %w", err)
145 }
146
147 if sysCtx.environSize, err = nullTerminatedByteCount(max, environ); err != nil {
148 return nil, fmt.Errorf("environ invalid: %w", err)
149 }
150
151 if randSource == nil {
152 sysCtx.randSource = platform.NewFakeRandSource()
153 } else {
154 sysCtx.randSource = randSource
155 }
156
157 if walltime != nil {
158 if clockResolutionInvalid(walltimeResolution) {
159 return nil, fmt.Errorf("invalid Walltime resolution: %d", walltimeResolution)
160 }
161 sysCtx.walltime = walltime
162 sysCtx.walltimeResolution = walltimeResolution
163 } else {
164 sysCtx.walltime = platform.NewFakeWalltime()
165 sysCtx.walltimeResolution = sys.ClockResolution(time.Microsecond.Nanoseconds())
166 }
167
168 if nanotime != nil {
169 if clockResolutionInvalid(nanotimeResolution) {
170 return nil, fmt.Errorf("invalid Nanotime resolution: %d", nanotimeResolution)
171 }
172 sysCtx.nanotime = nanotime
173 sysCtx.nanotimeResolution = nanotimeResolution
174 } else {
175 sysCtx.nanotime = platform.NewFakeNanotime()
176 sysCtx.nanotimeResolution = sys.ClockResolution(time.Nanosecond)
177 }
178
179 if nanosleep != nil {
180 sysCtx.nanosleep = nanosleep
181 } else {
182 sysCtx.nanosleep = platform.FakeNanosleep
183 }
184
185 if osyield != nil {
186 sysCtx.osyield = osyield
187 } else {
188 sysCtx.osyield = platform.FakeOsyield
189 }
190
191 err = sysCtx.InitFSContext(stdin, stdout, stderr, fs, guestPaths, tcpListeners)
192
193 return
194 }
195
196
197 func clockResolutionInvalid(resolution sys.ClockResolution) bool {
198 return resolution < 1 || resolution > sys.ClockResolution(time.Hour.Nanoseconds())
199 }
200
201
202
203 func nullTerminatedByteCount(max uint32, elements [][]byte) (uint32, error) {
204 count := uint32(len(elements))
205 if count > max {
206 return 0, errors.New("exceeds maximum count")
207 }
208
209
210
211 bufSize, maxSize := uint64(count), uint64(max)
212 for _, e := range elements {
213
214 for _, c := range e {
215 if c == 0 {
216 return 0, errors.New("contains NUL character")
217 }
218 }
219
220 nextSize := bufSize + uint64(len(e))
221 if nextSize > maxSize {
222 return 0, errors.New("exceeds maximum size")
223 }
224 bufSize = nextSize
225
226 }
227 return uint32(bufSize), nil
228 }
229
View as plain text