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 5package 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 19typedef struct { 20 uintptr_t a[20]; 21} S; 22 23S f() { 24 S *p; 25 26 p = (S *)(malloc(sizeof(S))); 27 p->a[0] = 0; 28 return *p; 29} 30*/ 31import "C" 32 33// allocateStack extends the stack so that stack copying doesn't 34// confuse the msan data structures. 35// 36//go:noinline 37func 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 49func 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 58func F2() interface{} { 59 return C.S{} 60} 61 62func 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 72func main() { 73 allocateStack(16384) 74 poisonStack(128) 75} 76