• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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