Skip to content

Commit a5900f9

Browse files
committed
Fix follower proxy TTL check and applyExpire overflow guard
- tryLeaderNonStringExists: check TTL key on leader before reporting non-string type existence; expired keys return false - applyExpire: add overflow guard for ttl*unit before time.Duration conversion, matching SET TTL parsing behavior
1 parent 7d1dedd commit a5900f9

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

adapter/redis.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,8 +830,15 @@ func (r *RedisServer) getHandleNone(conn redcon.Conn, key []byte, isLeader bool)
830830
}
831831

832832
// tryLeaderNonStringExists checks whether the key exists as a non-string type
833-
// (hash, set, zset, stream, HLL, or list) on the leader.
833+
// (hash, set, zset, stream, HLL, or list) on the leader. Returns false if the
834+
// key has an expired TTL.
834835
func (r *RedisServer) tryLeaderNonStringExists(key []byte) bool {
836+
// Check TTL first: if expired, the key is logically gone.
837+
if raw, err := r.tryLeaderGetAt(redisTTLKey(key), 0); err == nil {
838+
if ttl, decErr := decodeRedisTTL(raw); decErr == nil && !ttl.After(time.Now()) {
839+
return false
840+
}
841+
}
835842
for _, internalKey := range [][]byte{
836843
redisHashKey(key),
837844
redisSetKey(key),
@@ -1510,6 +1517,9 @@ func (t *txnContext) applyExpire(cmd redcon.Command, unit time.Duration) (redisR
15101517
if ttl <= 0 {
15111518
return t.stageKeyDeletion(cmd.Args[1])
15121519
}
1520+
if ttl > math.MaxInt64/int64(unit) {
1521+
return redisResult{}, errors.New("ERR invalid expire time in command")
1522+
}
15131523

15141524
expireAt := time.Now().Add(time.Duration(ttl) * unit)
15151525
state.value = &expireAt

0 commit comments

Comments
 (0)