1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 // A C function returning a value on the Go stack could leave the Go 8 // stack marked as uninitialized, potentially causing a later error 9 // when the stack is used for something else. Issue 26209. 10 11 /* 12 #cgo LDFLAGS: -fsanitize=memory 13 #cgo CPPFLAGS: -fsanitize=memory 14 15 #include <stdint.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 typedef struct { 20 uintptr_t a[20]; 21 } S; 22 23 S f() { 24 S *p; 25 26 p = (S *)(malloc(sizeof(S))); 27 p->a[0] = 0; 28 return *p; 29 } 30 */ 31 import "C" 32 33 // allocateStack extends the stack so that stack copying doesn't 34 // confuse the msan data structures. 35 // 36 //go:noinline 37 func allocateStack(i int) int { 38 if i == 0 { 39 return i 40 } 41 return allocateStack(i - 1) 42 } 43 44 // F1 marks a chunk of stack as uninitialized. 45 // C.f returns an uninitialized struct on the stack, so msan will mark 46 // the stack as uninitialized. 47 // 48 //go:noinline 49 func F1() uintptr { 50 s := C.f() 51 return uintptr(s.a[0]) 52 } 53 54 // F2 allocates a struct on the stack and converts it to an empty interface, 55 // which will call msanread and see that the data appears uninitialized. 56 // 57 //go:noinline 58 func F2() interface{} { 59 return C.S{} 60 } 61 62 func poisonStack(i int) int { 63 if i == 0 { 64 return int(F1()) 65 } 66 F1() 67 r := poisonStack(i - 1) 68 F2() 69 return r 70 } 71 72 func main() { 73 allocateStack(16384) 74 poisonStack(128) 75 } 76