mirror of
https://github.com/golang/go
synced 2024-11-14 15:00:27 -07:00
73 lines
1.4 KiB
Go
73 lines
1.4 KiB
Go
|
// 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)
|
||
|
}
|