// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// A C function returning a value on the Go stack could leave the Go
// stack marked as uninitialized, potentially causing a later error
// when the stack is used for something else. Issue 26209.
/*
#cgo LDFLAGS: -fsanitize=memory
#cgo CPPFLAGS: -fsanitize=memory
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
uintptr_t a[20];
} S;
S f() {
S *p;
p = (S *)(malloc(sizeof(S)));
p->a[0] = 0;
return *p;
}
*/
import "C"
// allocateStack extends the stack so that stack copying doesn't
// confuse the msan data structures.
//go:noinline
func allocateStack(i int) int {
if i == 0 {
return i
}
return allocateStack(i - 1)
}
// F1 marks a chunk of stack as uninitialized.
// C.f returns an uninitialized struct on the stack, so msan will mark
// the stack as uninitialized.
//go:noinline
func F1() uintptr {
s := C.f()
return uintptr(s.a[0])
}
// F2 allocates a struct on the stack and converts it to an empty interface,
// which will call msanread and see that the data appears uninitialized.
//go:noinline
func F2() interface{} {
return C.S{}
}
func poisonStack(i int) int {
if i == 0 {
return int(F1())
}
F1()
r := poisonStack(i - 1)
F2()
return r
}
func main() {
allocateStack(16384)
poisonStack(128)
}