1
1
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:
David McDonald 2022-12-17 02:18:48 -06:00
parent fa368bb790
commit 3232f9cc15
3 changed files with 35 additions and 44 deletions

View File

@ -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") },
)()

View File

@ -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 {

View 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
}