@@ -235,20 +235,41 @@ func Mprotect(b []byte, prot int) (err error) {
235235}
236236
237237func Environ () []string {
238- environ := libc_environ
239- var envs []string
240- for * environ != nil {
241- // Convert the C string to a Go string.
242- length := libc_strlen (* environ )
238+ // calculate total memory required
239+ var length uintptr
240+ var vars int
241+ for environ := libc_environ ; * environ != nil ; {
242+ length += libc_strlen (* environ )
243+ vars ++
244+ environ = (* unsafe .Pointer )(unsafe .Pointer (uintptr (unsafe .Pointer (environ )) + unsafe .Sizeof (environ )))
245+ }
246+
247+ // allocate our backing slice for the strings
248+ b := make ([]byte , length )
249+ // and the slice we're going to return
250+ envs := make ([]string , 0 , vars )
251+
252+ // loop over the environment again, this time copying over the data to the backing slice
253+ for environ := libc_environ ; * environ != nil ; {
254+ length = libc_strlen (* environ )
255+ // construct a Go string pointing at the libc-allocated environment variable data
243256 var envVar string
244257 rawEnvVar := (* struct {
245258 ptr unsafe.Pointer
246259 length uintptr
247260 })(unsafe .Pointer (& envVar ))
248261 rawEnvVar .ptr = * environ
249262 rawEnvVar .length = length
250- envs = append (envs , envVar )
251- // This is the Go equivalent of "environ++" in C.
263+ // pull off the number of bytes we need for this environment variable
264+ var bs []byte
265+ bs , b = b [:length ], b [length :]
266+ // copy over the bytes to the Go heap
267+ copy (bs , envVar )
268+ // convert trimmed slice to string
269+ s := * (* string )(unsafe .Pointer (& bs ))
270+ // add s to our list of environment variables
271+ envs = append (envs , s )
272+ // environ++
252273 environ = (* unsafe .Pointer )(unsafe .Pointer (uintptr (unsafe .Pointer (environ )) + unsafe .Sizeof (environ )))
253274 }
254275 return envs
0 commit comments