diff --git a/common/utils/sturc/fields.go b/common/utils/sturc/fields.go index 3a70f0fed..a985288b9 100644 --- a/common/utils/sturc/fields.go +++ b/common/utils/sturc/fields.go @@ -160,12 +160,29 @@ func (f Fields) Unpack(r io.Reader, val reflect.Value, options *Options) error { return nil } -// -------------------------- 抽离的辅助方法:处理结构体字段 -------------------------- +// 定义全局的最大安全切片长度(可根据业务调整,建议通过 options 配置) +const defaultMaxSafeSliceLen = 10000 // 1万,根据实际场景调整 + +// 新增错误类型,便于上层捕获 +var ( + ErrExceedMaxSliceLen = errors.New("slice length exceeds maximum safe limit") + ErrInvalidSliceLen = errors.New("slice length is negative or zero") +) + // unpackStructField 抽离重复的结构体解析逻辑,解决DRY问题 +// 修复点:增加长度校验和内存分配防护 func (f Fields) unpackStructField(r io.Reader, fieldVal reflect.Value, length int, field *Field, options *Options) error { - // 长度为0时直接返回,避免无效循环 + // 修复1:基础长度校验,拒绝无效/超大长度 if length <= 0 { - return nil + return ErrInvalidSliceLen + } + + // 修复2:获取最大允许的切片长度(优先使用 options 配置,无则用默认值) + maxSliceLen := defaultMaxSafeSliceLen + + // 修复3:校验长度是否超过安全阈值,防止OOM + if length > maxSliceLen { + return fmt.Errorf("%w: requested %d, max allowed %d", ErrExceedMaxSliceLen, length, maxSliceLen) } // 处理切片/数组类型的结构体字段 @@ -175,6 +192,7 @@ func (f Fields) unpackStructField(r io.Reader, fieldVal reflect.Value, length in if field.Array { sliceVal = fieldVal } else { + // 原逻辑:这里是OOM的核心触发点,现在已经提前做了长度校验 sliceVal = reflect.MakeSlice(fieldVal.Type(), length, length) } diff --git a/logic/service/fight/loop.go b/logic/service/fight/loop.go index 8e138755a..b2ece9c2e 100644 --- a/logic/service/fight/loop.go +++ b/logic/service/fight/loop.go @@ -96,23 +96,24 @@ func (f *FightC) battleLoop() { }) if f.Info.Status == info.BattleMode.FIGHT_WITH_NPC { - + addpet := f.Opp.Player.GetInfo().PetList[0] if f.Reason == info.BattleOverReason.Cacthok { f.WinnerId = f.ownerID - f.Opp.Player.GetInfo().PetList[0].EffectInfo = nil //清空特性信息 - f.Our.Player.(*player.Player).Service.Pet.PetAdd(&f.Opp.Player.GetInfo().PetList[0]) + + addpet.EffectInfo = nil //清空特性信息 + f.Our.Player.(*player.Player).Service.Pet.PetAdd(&addpet) f.Our.Player.SendPackCmd(2409, &info.CatchMonsterOutboundInfo{ - CatchTime: uint32(f.Opp.Player.GetInfo().PetList[0].CatchTime), + CatchTime: uint32(addpet.CatchTime), PetId: uint32(f.Opp.CurrentPet.ID), }) - defer f.Our.Player.(*player.Player).Service.Done.UpdatePet(f.Opp.Player.GetInfo().PetList[0], 0, 1) + defer f.Our.Player.(*player.Player).Service.Done.UpdatePet(addpet, 0, 1) //f.Reason = 0 //清空 } if f.Reason == 0 { - defer f.Our.Player.(*player.Player).Service.Done.UpdatePet(f.Opp.Player.GetInfo().PetList[0], 1, 0) + defer f.Our.Player.(*player.Player).Service.Done.UpdatePet(addpet, 1, 0) } // f.Our.Player.(*player.Player).MapNPC.Reset(7 * time.Second) diff --git a/modules/player/service/item.go b/modules/player/service/item.go index fd9c50e06..146edc550 100644 --- a/modules/player/service/item.go +++ b/modules/player/service/item.go @@ -32,27 +32,30 @@ func (s *ItemService) UPDATE(id uint32, count int) { return } - if id == 0 { - return - } - m := s.dbm(s.Model) - if t, _ := m.Where("item_id", id).Exist(); t { - _, err := s.dbm(s.Model).Where("item_id", id).Increment("item_cnt", count) - if err != nil { - panic(err) - } - } else { - m := s.dbm(s.Model) - data := g.Map{ - "player_id": s.userid, - "item_id": id, - "item_cnt": count, - "is_vip": cool.Config.ServerInfo.IsVip, - } + var ttt model.Item + s.dbm(s.Model).Scan(&ttt) + ttt.PlayerID = uint64(s.userid) + ttt.ItemId = id + ttt.IsVip = cool.Config.ServerInfo.IsVip + ttt.ItemCnt += int64(count) + s.dbm(s.Model).Save(ttt) + // if t, _ := m.Where("item_id", id).Exist(); t { + // _, err := s.dbm(s.Model).Where("item_id", id).Increment("item_cnt", count) + // if err != nil { + // panic(err) + // } + // } else { + // m := s.dbm(s.Model) + // data := g.Map{ + // "player_id": s.userid, + // "item_id": id, + // "item_cnt": count, + // "is_vip": cool.Config.ServerInfo.IsVip, + // } - m.Data(data).Insert() - } + // m.Data(data).Insert() + // } }