mirror of
https://github.com/wader/fq.git
synced 2024-11-23 00:57:15 +03:00
decode: moves PosLoopDetector into its own package
This commit is contained in:
parent
fa368bb790
commit
3232f9cc15
@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/wader/fq/format"
|
||||
"github.com/wader/fq/format/apple"
|
||||
"github.com/wader/fq/pkg/decode"
|
||||
"github.com/wader/fq/pkg/interp"
|
||||
"github.com/wader/fq/pkg/scalar"
|
||||
@ -299,32 +300,12 @@ const (
|
||||
dictEntrySize = 4
|
||||
)
|
||||
|
||||
type posLoopDetector []int64
|
||||
|
||||
func (pld *posLoopDetector) push(i int64, detect func()) {
|
||||
for _, o := range *pld {
|
||||
if i == o {
|
||||
detect()
|
||||
}
|
||||
}
|
||||
*pld = append(*pld, i)
|
||||
}
|
||||
|
||||
func (pld *posLoopDetector) pop() {
|
||||
*pld = (*pld)[:len(*pld)-1]
|
||||
}
|
||||
|
||||
func (pld *posLoopDetector) pushAndPop(i int64, detect func()) func() {
|
||||
pld.push(i, detect)
|
||||
return pld.pop
|
||||
}
|
||||
|
||||
func makeDecodeRecord() func(d *decode.D) {
|
||||
var pld posLoopDetector
|
||||
var pld apple.PosLoopDetector
|
||||
|
||||
var decodeRecord func(d *decode.D)
|
||||
decodeRecord = func(d *decode.D) {
|
||||
defer pld.pushAndPop(
|
||||
defer pld.PushAndPop(
|
||||
d.Pos(),
|
||||
func() { d.Fatalf("infinite recursion detected in record decode function") },
|
||||
)()
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/wader/fq/format"
|
||||
"github.com/wader/fq/format/apple"
|
||||
"github.com/wader/fq/pkg/decode"
|
||||
"github.com/wader/fq/pkg/interp"
|
||||
"github.com/wader/fq/pkg/scalar"
|
||||
@ -185,26 +186,6 @@ func decodeItem(d *decode.D, p *plist) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type indexStack []uint64
|
||||
|
||||
func (i *indexStack) pop() {
|
||||
*i = (*i)[:len(*i)-1]
|
||||
}
|
||||
|
||||
func (i *indexStack) push(idx uint64, handler func()) {
|
||||
for _, v := range *i {
|
||||
if v == idx {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
*i = append(*i, idx)
|
||||
}
|
||||
|
||||
func (i *indexStack) pushAndPop(idx uint64, handler func()) func() {
|
||||
i.push(idx, handler)
|
||||
return i.pop
|
||||
}
|
||||
|
||||
// decodeReference looks up and decodes an object based on its index in the
|
||||
// offset table. Returns a bool indicating whether or not the decoded item is
|
||||
// a string (necessary for checking dictionary key validity).
|
||||
@ -216,7 +197,7 @@ func (pl *plist) decodeReference(d *decode.D, idx uint64) bool {
|
||||
}
|
||||
pl.consumed[idx] = true
|
||||
|
||||
defer pl.idxStack.pushAndPop(idx, func() { d.Fatalf("infinite recursion detected") })()
|
||||
defer pl.pld.PushAndPop(int64(idx), func() { d.Fatalf("infinite recursion detected") })()
|
||||
|
||||
itemOffset := pl.o[idx]
|
||||
if itemOffset >= pl.t.offsetTableStart {
|
||||
@ -243,7 +224,7 @@ type plist struct {
|
||||
t trailer
|
||||
o []uint64
|
||||
consumed map[uint64]bool
|
||||
idxStack indexStack
|
||||
pld apple.PosLoopDetector
|
||||
}
|
||||
|
||||
func bplistDecode(d *decode.D, _ any) any {
|
||||
|
29
format/apple/loop_detector.go
Normal file
29
format/apple/loop_detector.go
Normal file
@ -0,0 +1,29 @@
|
||||
package apple
|
||||
|
||||
// PosLoopDetector is used for detecting loops when writing decoders, and can
|
||||
// short-circuit infinite recursion that can cause stack overflows.
|
||||
type PosLoopDetector []int64
|
||||
|
||||
// Push adds the current offset to the stack and executes the supplied
|
||||
// detection function
|
||||
func (pld *PosLoopDetector) Push(offset int64, detect func()) {
|
||||
for _, o := range *pld {
|
||||
if offset == o {
|
||||
detect()
|
||||
}
|
||||
}
|
||||
*pld = append(*pld, offset)
|
||||
}
|
||||
|
||||
// Pop removes the most recently added offset from the stack.
|
||||
func (pld *PosLoopDetector) Pop() {
|
||||
*pld = (*pld)[:len(*pld)-1]
|
||||
}
|
||||
|
||||
// PushAndPop adds the current offset to the stack, executes the supplied
|
||||
// detection function, and returns the Pop method. A good usage of this is to
|
||||
// pair this method call with a defer statement.
|
||||
func (pld *PosLoopDetector) PushAndPop(i int64, detect func()) func() {
|
||||
pld.Push(i, detect)
|
||||
return pld.Pop
|
||||
}
|
Loading…
Reference in New Issue
Block a user