Go Linter ในรูปแบบของ go vet เพื่อค้นหาการใช้งานที่ไม่ถูกต้องของ reflect.SliceHeader และ reflect.StringHeader และ casts ที่ไม่ปลอดภัยระหว่างโครงสร้างที่มีสนามขนาดสถาปัตยกรรม

go-safer รายงานรูปแบบการใช้งานดังต่อไปนี้:
reflect.StringHeader เกี่ยวกับประเภทพื้นฐาน reflect.SliceHeaderstring อิน reflect.StringHeader แตนซ์ของประเภท reflect.SliceHeaderint , uint หรือ uintptrรูปแบบ 1 ระบุรหัสที่มีลักษณะเช่นนี้:
func unsafeFunction ( s string ) [] byte {
sH := ( * reflect . StringHeader )( unsafe . Pointer ( & s ))
bH := & reflect. SliceHeader {
Data : sH . Data ,
Len : sH . Len ,
Cap : sH . Len ,
}
return * ( * [] byte )( unsafe . Pointer ( bH ))
} นอกจากนี้ยังจะจับกรณีที่ reflect.SliceHeader ถูกเปลี่ยนชื่อเช่นใน type MysteryType reflect.SliceHeader
รูปแบบ 2 ระบุรหัสเช่นต่อไปนี้:
func unsafeFunction ( s string ) [] byte {
strH := ( * reflect . StringHeader )( unsafe . Pointer ( & str ))
sH := ( * reflect . SliceHeader )( unsafe . Pointer ( nil ))
sH . Len = strH . Len
sH . Cap = strH . Len
sH . Data = strH . Data
return
} safer-go จะจับการมอบหมายไปยังวัตถุประเภท reflect.SliceHeader การใช้กราฟการไหลของการควบคุมของฟังก์ชั่นจะเห็นว่า sH ไม่ได้มาจากการหล่อชิ้นจริง (นี่คือ nil แทน)
รูปแบบ 3 ที่ระบุตัวตนดังต่อไปนี้:
type A struct {
x int
}
type B struct {
y int64
}
func unsafeFunction ( a A ) B {
return * ( * B )( unsafe . Pointer ( & a ))
} มีตัวอย่างเพิ่มเติมเกี่ยวกับรหัสที่ไม่ถูกต้อง (รายงาน) และรหัสที่ปลอดภัยในกรณีทดสอบในไดเรกทอรี passes/*/testdata/src
หาก reflect.SliceHeader หรือ reflect.StringHeader ไม่ได้ถูกสร้างขึ้นโดยการหล่อชิ้นหรือ string จริงแล้วรันไทม์ GO จะไม่ปฏิบัติต่อฟิลด์ Data ภายในประเภทเหล่านี้เป็นการอ้างอิงถึงอาร์เรย์ข้อมูลพื้นฐาน ดังนั้นหากนักสะสมขยะทำงานก่อนที่จะมีการหล่อสุดท้ายจากอินสแตนซ์ส่วนหัวตามตัวอักษรไปยังชิ้นหรือ string จริงมันอาจรวบรวมชิ้นหรือ string ดั้งเดิม สิ่งนี้สามารถนำไปสู่ช่องโหว่การรั่วไหลของข้อมูล
สำหรับรายละเอียดเพิ่มเติมเช่นการพิสูจน์แนวคิดเกี่ยวกับแนวคิดและข้อเสนอแนะสำหรับรูปแบบที่ไม่ปลอดภัยเหล่านี้เวอร์ชันที่คงที่อ่านโพสต์บล็อกนี้: Golang Slice Header Data Tata Rexpuron
ในการติดตั้ง go-safer ให้ใช้คำสั่งต่อไปนี้:
go get github.com/jlauinger/go-safer
สิ่งนี้จะติดตั้ง go-safer เป็น $GOPATH/bin ดังนั้นตรวจสอบให้แน่ใจว่ารวมอยู่ในตัวแปรสภาพแวดล้อม $PATH ของคุณ
เรียกใช้ go-safer บนแพ็คเกจแบบนี้:
$ go-safer example/cmd
หรือจัดหาหลายแพ็คเกจคั่นด้วยช่องว่าง:
$ go-safer example/cmd example/util strings
ในการตรวจสอบแพ็คเกจและนำเข้าทั้งหมดใช้ทั้งหมดใช้ ./... :
$ go-safer example/cmd/...
สุดท้ายเพื่อตรวจสอบแพ็คเกจในไดเรกทอรีปัจจุบันที่คุณสามารถ . -
$ go-safer .
go-safer ยอมรับธงเดียวกันกับ go vet :
Flags:
-V print version and exit
-all
no effect (deprecated)
-c int
display offending line with this many lines of context (default -1)
-cpuprofile string
write CPU profile to this file
-debug string
debug flags, any subset of "fpstv"
-fix
apply all suggested fixes
-flags
print analyzer flags in JSON
-json
emit JSON output
-memprofile string
write memory profile to this file
-source
no effect (deprecated)
-tags string
no effect (deprecated)
-trace string
write trace log to this file
-v no effect (deprecated)
การจัดหา -help Flag พิมพ์ข้อมูลการใช้งานสำหรับ go-safer :
$ go-safer -help
หากโครงการของคุณใช้โมดูล GO และไฟล์ go.mod go-safer จะดึงข้อมูลการพึ่งพาทั้งหมดโดยอัตโนมัติก่อนที่จะวิเคราะห์ มันทำงานเหมือน go build จะ
หากคุณใช้รูปแบบที่แตกต่างกันของการจัดการการพึ่งพาเช่นคู่มือ go get , go mod vendor หรือสิ่งอื่นใดคุณต้องเรียกใช้การจัดการการพึ่งพาของคุณก่อนที่จะใช้ go-safer เพื่อให้มีการพึ่งพาทั้งหมดก่อนการวิเคราะห์
ในการรับซอร์สโค้ดและรวบรวมไบนารีให้เรียกใช้สิ่งนี้:
$ git clone https://github.com/jlauinger/go-safer
$ cd go-safer
$ go build
ในการเรียกใช้กรณีทดสอบใช้คำสั่งต่อไปนี้:
$ go test ./...
go-safer ใช้โครงสร้างพื้นฐานการทดสอบจาก golang.org/x/tools/go/analysis/analysistest ในการเพิ่มกรณีทดสอบให้สร้างแพ็คเกจใหม่ภายในไดเรกทอรี bad หรือ good ใน passes/sliceheader/testdata/src เพิ่มไฟล์ GO จำนวนมากลงในแพ็คเกจตามต้องการ
จากนั้นลงทะเบียนแพ็คเกจใหม่ในไฟล์ sliceheader_test.go โดยระบุพา ธ แพ็คเกจ
ในไฟล์ต้นฉบับกรณีทดสอบเพิ่มความคิดเห็นคำอธิบายประกอบลงในบรรทัดที่ควรรายงาน (หรือไม่) ความคิดเห็นต้องมีลักษณะเช่นนี้:
sH.Len = strH.Len // want "assigning to reflect header object" "assigning to reflect header object"
fmt.Println("hello world") // ok
คำอธิบายประกอบที่ระบุบรรทัดที่ควรรายงานจะต้องเริ่มต้นด้วย want และจากนั้นมีข้อความที่ต้องการสองครั้ง ด้วยเหตุผลบางอย่างโครงสร้างพื้นฐานการทดสอบจะทำให้เกิด go-safer ออกคำอธิบายประกอบสองครั้งดังนั้นจึงต้องคาดว่าจะผ่านการทดสอบสองครั้ง
กรณีทดสอบสำหรับ structcast ผ่านสามารถเพิ่มได้ในทำนองเดียวกัน
เนื่องจาก go-safer ถูกสร้างขึ้นบนโครงสร้างพื้นฐานมาตรฐานของ Vet Vet คุณสามารถนำเข้าผ่านไปยัง Linter ที่ใช้สัตว์แพทย์ Go ได้
ได้รับใบอนุญาตภายใต้ใบอนุญาต MIT ("ใบอนุญาต") คุณไม่สามารถใช้โครงการนี้ยกเว้นตามใบอนุญาต คุณอาจได้รับสำเนาใบอนุญาตที่นี่
ลิขสิทธิ์ 2020 Johannes Lauinger
เครื่องมือนี้ได้รับการพัฒนาเป็นส่วนหนึ่งของวิทยานิพนธ์ปริญญาโทของฉันที่กลุ่มเทคโนโลยีซอฟต์แวร์ที่ TU Darmstadt