msan6.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. package main
  5. // A C function returning a value on the Go stack could leave the Go
  6. // stack marked as uninitialized, potentially causing a later error
  7. // when the stack is used for something else. Issue 26209.
  8. /*
  9. #cgo LDFLAGS: -fsanitize=memory
  10. #cgo CPPFLAGS: -fsanitize=memory
  11. #include <stdint.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. typedef struct {
  15. uintptr_t a[20];
  16. } S;
  17. S f() {
  18. S *p;
  19. p = (S *)(malloc(sizeof(S)));
  20. p->a[0] = 0;
  21. return *p;
  22. }
  23. */
  24. import "C"
  25. // allocateStack extends the stack so that stack copying doesn't
  26. // confuse the msan data structures.
  27. //go:noinline
  28. func allocateStack(i int) int {
  29. if i == 0 {
  30. return i
  31. }
  32. return allocateStack(i - 1)
  33. }
  34. // F1 marks a chunk of stack as uninitialized.
  35. // C.f returns an uninitialized struct on the stack, so msan will mark
  36. // the stack as uninitialized.
  37. //go:noinline
  38. func F1() uintptr {
  39. s := C.f()
  40. return uintptr(s.a[0])
  41. }
  42. // F2 allocates a struct on the stack and converts it to an empty interface,
  43. // which will call msanread and see that the data appears uninitialized.
  44. //go:noinline
  45. func F2() interface{} {
  46. return C.S{}
  47. }
  48. func poisonStack(i int) int {
  49. if i == 0 {
  50. return int(F1())
  51. }
  52. F1()
  53. r := poisonStack(i - 1)
  54. F2()
  55. return r
  56. }
  57. func main() {
  58. allocateStack(16384)
  59. poisonStack(128)
  60. }