1// Copyright 2019 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 runtime
6
7import "unsafe"
8
9func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
10	// Check that (*[n]elem)(p) is appropriately aligned.
11	// TODO(mdempsky): What about fieldAlign?
12	if uintptr(p)&(uintptr(elem.align)-1) != 0 {
13		throw("checkptr: unsafe pointer conversion")
14	}
15
16	// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
17	if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
18		throw("checkptr: unsafe pointer conversion")
19	}
20}
21
22func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
23	if 0 < uintptr(p) && uintptr(p) < minLegalPointer {
24		throw("checkptr: unsafe pointer arithmetic")
25	}
26
27	// Check that if the computed pointer p points into a heap
28	// object, then one of the original pointers must have pointed
29	// into the same object.
30	base := checkptrBase(p)
31	if base == 0 {
32		return
33	}
34
35	for _, original := range originals {
36		if base == checkptrBase(original) {
37			return
38		}
39	}
40
41	throw("checkptr: unsafe pointer arithmetic")
42}
43
44// checkptrBase returns the base address for the allocation containing
45// the address p.
46//
47// Importantly, if p1 and p2 point into the same variable, then
48// checkptrBase(p1) == checkptrBase(p2). However, the converse/inverse
49// is not necessarily true as allocations can have trailing padding,
50// and multiple variables may be packed into a single allocation.
51func checkptrBase(p unsafe.Pointer) uintptr {
52	// stack
53	if gp := getg(); gp.stack.lo <= uintptr(p) && uintptr(p) < gp.stack.hi {
54		// TODO(mdempsky): Walk the stack to identify the
55		// specific stack frame or even stack object that p
56		// points into.
57		//
58		// In the mean time, use "1" as a pseudo-address to
59		// represent the stack. This is an invalid address on
60		// all platforms, so it's guaranteed to be distinct
61		// from any of the addresses we might return below.
62		return 1
63	}
64
65	// heap (must check after stack because of #35068)
66	if base, _, _ := findObject(uintptr(p), 0, 0); base != 0 {
67		return base
68	}
69
70	// data or bss
71	for _, datap := range activeModules() {
72		if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
73			return datap.data
74		}
75		if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
76			return datap.bss
77		}
78	}
79
80	return 0
81}
82