mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2024-12-11 22:35:40 +01:00
af0629856c
Tests cover most of the cache and download related code paths and specify the expected result of various starting states and external failure modes. Where the current code's behaviour doesn't match a test's expectations, the test is disabled and annotated with a TODO until it can be fixed. Added dependency on `github.com/powerman/check` and ran `go mod vendor`.
146 lines
4.6 KiB
Go
146 lines
4.6 KiB
Go
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
|
//
|
|
// Permission to use, copy, modify, and distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
|
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
|
// tag is deprecated and thus should not be used.
|
|
// Go versions prior to 1.4 are disabled because they use a different layout
|
|
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
|
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
|
|
|
package spew
|
|
|
|
import (
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
// UnsafeDisabled is a build-time constant which specifies whether or
|
|
// not access to the unsafe package is available.
|
|
UnsafeDisabled = false
|
|
|
|
// ptrSize is the size of a pointer on the current arch.
|
|
ptrSize = unsafe.Sizeof((*byte)(nil))
|
|
)
|
|
|
|
type flag uintptr
|
|
|
|
var (
|
|
// flagRO indicates whether the value field of a reflect.Value
|
|
// is read-only.
|
|
flagRO flag
|
|
|
|
// flagAddr indicates whether the address of the reflect.Value's
|
|
// value may be taken.
|
|
flagAddr flag
|
|
)
|
|
|
|
// flagKindMask holds the bits that make up the kind
|
|
// part of the flags field. In all the supported versions,
|
|
// it is in the lower 5 bits.
|
|
const flagKindMask = flag(0x1f)
|
|
|
|
// Different versions of Go have used different
|
|
// bit layouts for the flags type. This table
|
|
// records the known combinations.
|
|
var okFlags = []struct {
|
|
ro, addr flag
|
|
}{{
|
|
// From Go 1.4 to 1.5
|
|
ro: 1 << 5,
|
|
addr: 1 << 7,
|
|
}, {
|
|
// Up to Go tip.
|
|
ro: 1<<5 | 1<<6,
|
|
addr: 1 << 8,
|
|
}}
|
|
|
|
var flagValOffset = func() uintptr {
|
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
|
if !ok {
|
|
panic("reflect.Value has no flag field")
|
|
}
|
|
return field.Offset
|
|
}()
|
|
|
|
// flagField returns a pointer to the flag field of a reflect.Value.
|
|
func flagField(v *reflect.Value) *flag {
|
|
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
|
}
|
|
|
|
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
|
// the typical safety restrictions preventing access to unaddressable and
|
|
// unexported data. It works by digging the raw pointer to the underlying
|
|
// value out of the protected value and generating a new unprotected (unsafe)
|
|
// reflect.Value to it.
|
|
//
|
|
// This allows us to check for implementations of the Stringer and error
|
|
// interfaces to be used for pretty printing ordinarily unaddressable and
|
|
// inaccessible values such as unexported struct fields.
|
|
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
|
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
|
|
return v
|
|
}
|
|
flagFieldPtr := flagField(&v)
|
|
*flagFieldPtr &^= flagRO
|
|
*flagFieldPtr |= flagAddr
|
|
return v
|
|
}
|
|
|
|
// Sanity checks against future reflect package changes
|
|
// to the type or semantics of the Value.flag field.
|
|
func init() {
|
|
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
|
if !ok {
|
|
panic("reflect.Value has no flag field")
|
|
}
|
|
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
|
panic("reflect.Value flag field has changed kind")
|
|
}
|
|
type t0 int
|
|
var t struct {
|
|
A t0
|
|
// t0 will have flagEmbedRO set.
|
|
t0
|
|
// a will have flagStickyRO set
|
|
a t0
|
|
}
|
|
vA := reflect.ValueOf(t).FieldByName("A")
|
|
va := reflect.ValueOf(t).FieldByName("a")
|
|
vt0 := reflect.ValueOf(t).FieldByName("t0")
|
|
|
|
// Infer flagRO from the difference between the flags
|
|
// for the (otherwise identical) fields in t.
|
|
flagPublic := *flagField(&vA)
|
|
flagWithRO := *flagField(&va) | *flagField(&vt0)
|
|
flagRO = flagPublic ^ flagWithRO
|
|
|
|
// Infer flagAddr from the difference between a value
|
|
// taken from a pointer and not.
|
|
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
|
|
flagNoPtr := *flagField(&vA)
|
|
flagPtr := *flagField(&vPtrA)
|
|
flagAddr = flagNoPtr ^ flagPtr
|
|
|
|
// Check that the inferred flags tally with one of the known versions.
|
|
for _, f := range okFlags {
|
|
if flagRO == f.ro && flagAddr == f.addr {
|
|
return
|
|
}
|
|
}
|
|
panic("reflect.Value read-only flag has changed semantics")
|
|
}
|