fix(access_log): fix slice out-of-bound panic on log rotation

This commit is contained in:
yusing
2025-12-16 17:20:59 +08:00
parent 6f9f995100
commit e44ecc0ccc
2 changed files with 31 additions and 20 deletions

View File

@@ -94,6 +94,7 @@ const (
)
var bytesPool = synk.GetUnsizedBytesPool()
var sizedPool = synk.GetSizedBytesPool()
func NewAccessLogger(parent task.Parent, cfg AnyConfig) (AccessLogger, error) {
writers, err := cfg.Writers()

View File

@@ -3,12 +3,11 @@ package accesslog
import (
"bytes"
"errors"
"fmt"
"io"
"slices"
"time"
"github.com/rs/zerolog"
gperr "github.com/yusing/goutils/errs"
"github.com/yusing/goutils/mockable"
strutils "github.com/yusing/goutils/strings"
)
@@ -164,31 +163,14 @@ func rotateLogFileByPolicy(file supportRotate, config *Retention, result *Rotate
// Read each line and write it to the beginning of the file
writePos := int64(0)
buf := bytesPool.Get()
defer func() {
bytesPool.Put(buf)
}()
// in reverse order to keep the order of the lines (from old to new)
for i := len(linesToKeep) - 1; i >= 0; i-- {
line := linesToKeep[i]
n := line.Size
if cap(buf) < int(n) {
buf = slices.Grow(buf, int(n)-cap(buf))
}
buf = buf[:n]
// Read the line from its original position
if _, err := file.ReadAt(buf, line.Pos); err != nil {
if err := fileContentMove(file, line.Pos, writePos, int(n)); err != nil {
return false, err
}
// Write it to the new position
if _, err := file.WriteAt(buf, writePos); err != nil {
return false, err
} else if n < line.Size {
return false, gperr.Errorf("%w, writing %d bytes, only %d written", io.ErrShortWrite, line.Size, n)
}
writePos += n
}
@@ -199,6 +181,34 @@ func rotateLogFileByPolicy(file supportRotate, config *Retention, result *Rotate
return true, nil
}
// fileContentMove moves the content of the file from the source position to the destination position.
//
// this is only used for moving from the back to the front of the file.
func fileContentMove(file supportRotate, srcPos, dstPos int64, size int) error {
buf := sizedPool.GetSized(size)
defer sizedPool.Put(buf)
// Read the line from its original position
nRead, err := file.ReadAt(buf, srcPos)
if err != nil {
return err
}
if nRead != size {
return fmt.Errorf("%w, reading %d bytes, only %d read", io.ErrShortBuffer, size, nRead)
}
// Write it to the new position
nWritten, err := file.WriteAt(buf, dstPos)
if err != nil {
return err
}
if nWritten != size {
return fmt.Errorf("%w, writing %d bytes, only %d written", io.ErrShortWrite, size, nWritten)
}
return nil
}
// rotateLogFileBySize rotates the log file by size.
// It returns the result of the rotation and an error if any.
//