$ git cherry --abbrev -v 8afd9cbb6cfb 66fb7fc33547 + 63b25c1 Fix typo in README (#235) + 419c929 G107 - SSRF (#236) + 145f1a0 Removed wrapping feature (#238) + ec32ce6 Support Go 1.11 (#239) + 762ff3a Allow quoted strings to be used to format SQL queries (#240) + 7f6509a Update README.md (#246) + 5f98926 Refactor Dockerfile (#245) + d3f1980 Fix false positives for SQL string concatenation with constants from another file (#247) + 64d58c2 Refactor the test code sample to support multiple files per sample + 1ecd47e bump Dockerfile golang from 1.10 to 1.11 + 027dc2b This fixes the html template when using '-fmt=html' - resolves HTML escaping issues within the template - resolves reference issues to reportInfo struct i.e. issues -> Issues, metrics -> Stats + 8c09a83 Add install.sh script + 97bc137 Add CI Installation steps and correct markdown lint errors + 3116b07 Fix typos in comments and rulelist (#256) + 443f84f Fix golint link (#263) + 4180994 Make G201 ignore CallExpr with no args (#262) + 9b966a4 add test case for strings.Builder G104 whitelist inclusion + adb4222 whitelist strings.Builder method in rule G104 + ae82798 Fix the WriteSring test by handling the error + 2695567 Build the code sample for string builder only fron Go 1.10 onwards + f14f17f Add a helper function which extracts the string parameters values of a call expression + 9b32fca Fix the bind rule to handle the case when the arguments of the net.Listen are returned by a function call + 24e3094 Extend the bind rule to handle the case when the net.Listen address in provided from a const + 72e95e8 Geneate and upload the test coverage report to codecove.io + 12400f9 Update README with the code coverage batch + 14ed63d Do not flag the unhandled errors which are explicitly ignored + f87af5f Detect the unhandled errors even though they are explicitly ignored if the 'audit: enabled' setting is defined in the global configuration (#274) + 5d33e6e Update the README with some details about the configuration file + b662615 Fix typo + a966ff7 Fix -conf example in README.md + 04ce7ba add a no-fail flag + e2752bc revert to default GOPATH if necessary (#279) - c04360f make API + 66fb7fc Replace import paths
		
			
				
	
	
		
			420 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			420 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2013-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.
 | 
						|
 */
 | 
						|
 | 
						|
package spew
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// supportedFlags is a list of all the character flags supported by fmt package.
 | 
						|
const supportedFlags = "0-+# "
 | 
						|
 | 
						|
// formatState implements the fmt.Formatter interface and contains information
 | 
						|
// about the state of a formatting operation.  The NewFormatter function can
 | 
						|
// be used to get a new Formatter which can be used directly as arguments
 | 
						|
// in standard fmt package printing calls.
 | 
						|
type formatState struct {
 | 
						|
	value          interface{}
 | 
						|
	fs             fmt.State
 | 
						|
	depth          int
 | 
						|
	pointers       map[uintptr]int
 | 
						|
	ignoreNextType bool
 | 
						|
	cs             *ConfigState
 | 
						|
}
 | 
						|
 | 
						|
// buildDefaultFormat recreates the original format string without precision
 | 
						|
// and width information to pass in to fmt.Sprintf in the case of an
 | 
						|
// unrecognized type.  Unless new types are added to the language, this
 | 
						|
// function won't ever be called.
 | 
						|
func (f *formatState) buildDefaultFormat() (format string) {
 | 
						|
	buf := bytes.NewBuffer(percentBytes)
 | 
						|
 | 
						|
	for _, flag := range supportedFlags {
 | 
						|
		if f.fs.Flag(int(flag)) {
 | 
						|
			buf.WriteRune(flag)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	buf.WriteRune('v')
 | 
						|
 | 
						|
	format = buf.String()
 | 
						|
	return format
 | 
						|
}
 | 
						|
 | 
						|
// constructOrigFormat recreates the original format string including precision
 | 
						|
// and width information to pass along to the standard fmt package.  This allows
 | 
						|
// automatic deferral of all format strings this package doesn't support.
 | 
						|
func (f *formatState) constructOrigFormat(verb rune) (format string) {
 | 
						|
	buf := bytes.NewBuffer(percentBytes)
 | 
						|
 | 
						|
	for _, flag := range supportedFlags {
 | 
						|
		if f.fs.Flag(int(flag)) {
 | 
						|
			buf.WriteRune(flag)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if width, ok := f.fs.Width(); ok {
 | 
						|
		buf.WriteString(strconv.Itoa(width))
 | 
						|
	}
 | 
						|
 | 
						|
	if precision, ok := f.fs.Precision(); ok {
 | 
						|
		buf.Write(precisionBytes)
 | 
						|
		buf.WriteString(strconv.Itoa(precision))
 | 
						|
	}
 | 
						|
 | 
						|
	buf.WriteRune(verb)
 | 
						|
 | 
						|
	format = buf.String()
 | 
						|
	return format
 | 
						|
}
 | 
						|
 | 
						|
// unpackValue returns values inside of non-nil interfaces when possible and
 | 
						|
// ensures that types for values which have been unpacked from an interface
 | 
						|
// are displayed when the show types flag is also set.
 | 
						|
// This is useful for data types like structs, arrays, slices, and maps which
 | 
						|
// can contain varying types packed inside an interface.
 | 
						|
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
 | 
						|
	if v.Kind() == reflect.Interface {
 | 
						|
		f.ignoreNextType = false
 | 
						|
		if !v.IsNil() {
 | 
						|
			v = v.Elem()
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return v
 | 
						|
}
 | 
						|
 | 
						|
// formatPtr handles formatting of pointers by indirecting them as necessary.
 | 
						|
func (f *formatState) formatPtr(v reflect.Value) {
 | 
						|
	// Display nil if top level pointer is nil.
 | 
						|
	showTypes := f.fs.Flag('#')
 | 
						|
	if v.IsNil() && (!showTypes || f.ignoreNextType) {
 | 
						|
		f.fs.Write(nilAngleBytes)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// Remove pointers at or below the current depth from map used to detect
 | 
						|
	// circular refs.
 | 
						|
	for k, depth := range f.pointers {
 | 
						|
		if depth >= f.depth {
 | 
						|
			delete(f.pointers, k)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Keep list of all dereferenced pointers to possibly show later.
 | 
						|
	pointerChain := make([]uintptr, 0)
 | 
						|
 | 
						|
	// Figure out how many levels of indirection there are by derferencing
 | 
						|
	// pointers and unpacking interfaces down the chain while detecting circular
 | 
						|
	// references.
 | 
						|
	nilFound := false
 | 
						|
	cycleFound := false
 | 
						|
	indirects := 0
 | 
						|
	ve := v
 | 
						|
	for ve.Kind() == reflect.Ptr {
 | 
						|
		if ve.IsNil() {
 | 
						|
			nilFound = true
 | 
						|
			break
 | 
						|
		}
 | 
						|
		indirects++
 | 
						|
		addr := ve.Pointer()
 | 
						|
		pointerChain = append(pointerChain, addr)
 | 
						|
		if pd, ok := f.pointers[addr]; ok && pd < f.depth {
 | 
						|
			cycleFound = true
 | 
						|
			indirects--
 | 
						|
			break
 | 
						|
		}
 | 
						|
		f.pointers[addr] = f.depth
 | 
						|
 | 
						|
		ve = ve.Elem()
 | 
						|
		if ve.Kind() == reflect.Interface {
 | 
						|
			if ve.IsNil() {
 | 
						|
				nilFound = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
			ve = ve.Elem()
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Display type or indirection level depending on flags.
 | 
						|
	if showTypes && !f.ignoreNextType {
 | 
						|
		f.fs.Write(openParenBytes)
 | 
						|
		f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
 | 
						|
		f.fs.Write([]byte(ve.Type().String()))
 | 
						|
		f.fs.Write(closeParenBytes)
 | 
						|
	} else {
 | 
						|
		if nilFound || cycleFound {
 | 
						|
			indirects += strings.Count(ve.Type().String(), "*")
 | 
						|
		}
 | 
						|
		f.fs.Write(openAngleBytes)
 | 
						|
		f.fs.Write([]byte(strings.Repeat("*", indirects)))
 | 
						|
		f.fs.Write(closeAngleBytes)
 | 
						|
	}
 | 
						|
 | 
						|
	// Display pointer information depending on flags.
 | 
						|
	if f.fs.Flag('+') && (len(pointerChain) > 0) {
 | 
						|
		f.fs.Write(openParenBytes)
 | 
						|
		for i, addr := range pointerChain {
 | 
						|
			if i > 0 {
 | 
						|
				f.fs.Write(pointerChainBytes)
 | 
						|
			}
 | 
						|
			printHexPtr(f.fs, addr)
 | 
						|
		}
 | 
						|
		f.fs.Write(closeParenBytes)
 | 
						|
	}
 | 
						|
 | 
						|
	// Display dereferenced value.
 | 
						|
	switch {
 | 
						|
	case nilFound:
 | 
						|
		f.fs.Write(nilAngleBytes)
 | 
						|
 | 
						|
	case cycleFound:
 | 
						|
		f.fs.Write(circularShortBytes)
 | 
						|
 | 
						|
	default:
 | 
						|
		f.ignoreNextType = true
 | 
						|
		f.format(ve)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// format is the main workhorse for providing the Formatter interface.  It
 | 
						|
// uses the passed reflect value to figure out what kind of object we are
 | 
						|
// dealing with and formats it appropriately.  It is a recursive function,
 | 
						|
// however circular data structures are detected and handled properly.
 | 
						|
func (f *formatState) format(v reflect.Value) {
 | 
						|
	// Handle invalid reflect values immediately.
 | 
						|
	kind := v.Kind()
 | 
						|
	if kind == reflect.Invalid {
 | 
						|
		f.fs.Write(invalidAngleBytes)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// Handle pointers specially.
 | 
						|
	if kind == reflect.Ptr {
 | 
						|
		f.formatPtr(v)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// Print type information unless already handled elsewhere.
 | 
						|
	if !f.ignoreNextType && f.fs.Flag('#') {
 | 
						|
		f.fs.Write(openParenBytes)
 | 
						|
		f.fs.Write([]byte(v.Type().String()))
 | 
						|
		f.fs.Write(closeParenBytes)
 | 
						|
	}
 | 
						|
	f.ignoreNextType = false
 | 
						|
 | 
						|
	// Call Stringer/error interfaces if they exist and the handle methods
 | 
						|
	// flag is enabled.
 | 
						|
	if !f.cs.DisableMethods {
 | 
						|
		if (kind != reflect.Invalid) && (kind != reflect.Interface) {
 | 
						|
			if handled := handleMethods(f.cs, f.fs, v); handled {
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	switch kind {
 | 
						|
	case reflect.Invalid:
 | 
						|
		// Do nothing.  We should never get here since invalid has already
 | 
						|
		// been handled above.
 | 
						|
 | 
						|
	case reflect.Bool:
 | 
						|
		printBool(f.fs, v.Bool())
 | 
						|
 | 
						|
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
 | 
						|
		printInt(f.fs, v.Int(), 10)
 | 
						|
 | 
						|
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | 
						|
		printUint(f.fs, v.Uint(), 10)
 | 
						|
 | 
						|
	case reflect.Float32:
 | 
						|
		printFloat(f.fs, v.Float(), 32)
 | 
						|
 | 
						|
	case reflect.Float64:
 | 
						|
		printFloat(f.fs, v.Float(), 64)
 | 
						|
 | 
						|
	case reflect.Complex64:
 | 
						|
		printComplex(f.fs, v.Complex(), 32)
 | 
						|
 | 
						|
	case reflect.Complex128:
 | 
						|
		printComplex(f.fs, v.Complex(), 64)
 | 
						|
 | 
						|
	case reflect.Slice:
 | 
						|
		if v.IsNil() {
 | 
						|
			f.fs.Write(nilAngleBytes)
 | 
						|
			break
 | 
						|
		}
 | 
						|
		fallthrough
 | 
						|
 | 
						|
	case reflect.Array:
 | 
						|
		f.fs.Write(openBracketBytes)
 | 
						|
		f.depth++
 | 
						|
		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
 | 
						|
			f.fs.Write(maxShortBytes)
 | 
						|
		} else {
 | 
						|
			numEntries := v.Len()
 | 
						|
			for i := 0; i < numEntries; i++ {
 | 
						|
				if i > 0 {
 | 
						|
					f.fs.Write(spaceBytes)
 | 
						|
				}
 | 
						|
				f.ignoreNextType = true
 | 
						|
				f.format(f.unpackValue(v.Index(i)))
 | 
						|
			}
 | 
						|
		}
 | 
						|
		f.depth--
 | 
						|
		f.fs.Write(closeBracketBytes)
 | 
						|
 | 
						|
	case reflect.String:
 | 
						|
		f.fs.Write([]byte(v.String()))
 | 
						|
 | 
						|
	case reflect.Interface:
 | 
						|
		// The only time we should get here is for nil interfaces due to
 | 
						|
		// unpackValue calls.
 | 
						|
		if v.IsNil() {
 | 
						|
			f.fs.Write(nilAngleBytes)
 | 
						|
		}
 | 
						|
 | 
						|
	case reflect.Ptr:
 | 
						|
		// Do nothing.  We should never get here since pointers have already
 | 
						|
		// been handled above.
 | 
						|
 | 
						|
	case reflect.Map:
 | 
						|
		// nil maps should be indicated as different than empty maps
 | 
						|
		if v.IsNil() {
 | 
						|
			f.fs.Write(nilAngleBytes)
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		f.fs.Write(openMapBytes)
 | 
						|
		f.depth++
 | 
						|
		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
 | 
						|
			f.fs.Write(maxShortBytes)
 | 
						|
		} else {
 | 
						|
			keys := v.MapKeys()
 | 
						|
			if f.cs.SortKeys {
 | 
						|
				sortValues(keys, f.cs)
 | 
						|
			}
 | 
						|
			for i, key := range keys {
 | 
						|
				if i > 0 {
 | 
						|
					f.fs.Write(spaceBytes)
 | 
						|
				}
 | 
						|
				f.ignoreNextType = true
 | 
						|
				f.format(f.unpackValue(key))
 | 
						|
				f.fs.Write(colonBytes)
 | 
						|
				f.ignoreNextType = true
 | 
						|
				f.format(f.unpackValue(v.MapIndex(key)))
 | 
						|
			}
 | 
						|
		}
 | 
						|
		f.depth--
 | 
						|
		f.fs.Write(closeMapBytes)
 | 
						|
 | 
						|
	case reflect.Struct:
 | 
						|
		numFields := v.NumField()
 | 
						|
		f.fs.Write(openBraceBytes)
 | 
						|
		f.depth++
 | 
						|
		if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
 | 
						|
			f.fs.Write(maxShortBytes)
 | 
						|
		} else {
 | 
						|
			vt := v.Type()
 | 
						|
			for i := 0; i < numFields; i++ {
 | 
						|
				if i > 0 {
 | 
						|
					f.fs.Write(spaceBytes)
 | 
						|
				}
 | 
						|
				vtf := vt.Field(i)
 | 
						|
				if f.fs.Flag('+') || f.fs.Flag('#') {
 | 
						|
					f.fs.Write([]byte(vtf.Name))
 | 
						|
					f.fs.Write(colonBytes)
 | 
						|
				}
 | 
						|
				f.format(f.unpackValue(v.Field(i)))
 | 
						|
			}
 | 
						|
		}
 | 
						|
		f.depth--
 | 
						|
		f.fs.Write(closeBraceBytes)
 | 
						|
 | 
						|
	case reflect.Uintptr:
 | 
						|
		printHexPtr(f.fs, uintptr(v.Uint()))
 | 
						|
 | 
						|
	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
 | 
						|
		printHexPtr(f.fs, v.Pointer())
 | 
						|
 | 
						|
	// There were not any other types at the time this code was written, but
 | 
						|
	// fall back to letting the default fmt package handle it if any get added.
 | 
						|
	default:
 | 
						|
		format := f.buildDefaultFormat()
 | 
						|
		if v.CanInterface() {
 | 
						|
			fmt.Fprintf(f.fs, format, v.Interface())
 | 
						|
		} else {
 | 
						|
			fmt.Fprintf(f.fs, format, v.String())
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
 | 
						|
// details.
 | 
						|
func (f *formatState) Format(fs fmt.State, verb rune) {
 | 
						|
	f.fs = fs
 | 
						|
 | 
						|
	// Use standard formatting for verbs that are not v.
 | 
						|
	if verb != 'v' {
 | 
						|
		format := f.constructOrigFormat(verb)
 | 
						|
		fmt.Fprintf(fs, format, f.value)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if f.value == nil {
 | 
						|
		if fs.Flag('#') {
 | 
						|
			fs.Write(interfaceBytes)
 | 
						|
		}
 | 
						|
		fs.Write(nilAngleBytes)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	f.format(reflect.ValueOf(f.value))
 | 
						|
}
 | 
						|
 | 
						|
// newFormatter is a helper function to consolidate the logic from the various
 | 
						|
// public methods which take varying config states.
 | 
						|
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
 | 
						|
	fs := &formatState{value: v, cs: cs}
 | 
						|
	fs.pointers = make(map[uintptr]int)
 | 
						|
	return fs
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
 | 
						|
interface.  As a result, it integrates cleanly with standard fmt package
 | 
						|
printing functions.  The formatter is useful for inline printing of smaller data
 | 
						|
types similar to the standard %v format specifier.
 | 
						|
 | 
						|
The custom formatter only responds to the %v (most compact), %+v (adds pointer
 | 
						|
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
 | 
						|
combinations.  Any other verbs such as %x and %q will be sent to the the
 | 
						|
standard fmt package for formatting.  In addition, the custom formatter ignores
 | 
						|
the width and precision arguments (however they will still work on the format
 | 
						|
specifiers not handled by the custom formatter).
 | 
						|
 | 
						|
Typically this function shouldn't be called directly.  It is much easier to make
 | 
						|
use of the custom formatter by calling one of the convenience functions such as
 | 
						|
Printf, Println, or Fprintf.
 | 
						|
*/
 | 
						|
func NewFormatter(v interface{}) fmt.Formatter {
 | 
						|
	return newFormatter(&Config, v)
 | 
						|
}
 |