mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-29 17:32:17 -07:00
Harden offsetCardCounter() against signed-int overflow
Replace the raw oldValue + offset sum with addClamped(), clamping to [0, MAX_COUNTER_VALUE] without overflow.
This commit is contained in:
parent
3aa94b4f31
commit
2a1b505913
2 changed files with 11 additions and 7 deletions
|
|
@ -27,6 +27,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||||
|
#include <libcockatrice/utility/clamped_arithmetic.h>
|
||||||
#include <libcockatrice/utility/expression.h>
|
#include <libcockatrice/utility/expression.h>
|
||||||
#include <libcockatrice/utility/trice_limits.h>
|
#include <libcockatrice/utility/trice_limits.h>
|
||||||
#include <libcockatrice/utility/zone_names.h>
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
@ -1530,12 +1531,15 @@ void PlayerActions::offsetCardCounter(QList<CardItem *> selectedCards, int count
|
||||||
QList<const ::google::protobuf::Message *> commandList;
|
QList<const ::google::protobuf::Message *> commandList;
|
||||||
for (auto card : selectedCards) {
|
for (auto card : selectedCards) {
|
||||||
int oldValue = card->getCounters().value(counterId, 0);
|
int oldValue = card->getCounters().value(counterId, 0);
|
||||||
int newValue = oldValue + offset;
|
|
||||||
|
|
||||||
// Early exit optimization: server enforces [0, MAX_COUNTER_VALUE].
|
// Overflow-safe clamp to the server-enforced range [0, MAX_COUNTER_VALUE];
|
||||||
// Compare clamped value to allow recovery from invalid states.
|
// a result differing from oldValue also corrects an out-of-range cached value.
|
||||||
int clampedValue = qBound(0, newValue, MAX_COUNTER_VALUE);
|
// Callers only ever pass offset == ±1 (actAddCardCounter / actRemoveCardCounter).
|
||||||
if (clampedValue != oldValue) {
|
// This client-side clamp is a defense-in-depth UX check, consistent with
|
||||||
|
// actSetCardCounter and actIncrementAllCardCounters; the server remains the
|
||||||
|
// authoritative enforcer of the bounds.
|
||||||
|
int newValue = addClamped(oldValue, offset, 0, MAX_COUNTER_VALUE);
|
||||||
|
if (newValue != oldValue) {
|
||||||
auto *cmd = new Command_SetCardCounter;
|
auto *cmd = new Command_SetCardCounter;
|
||||||
cmd->set_zone(card->getZone()->getName().toStdString());
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
||||||
cmd->set_card_id(card->getId());
|
cmd->set_card_id(card->getId());
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
/**
|
/**
|
||||||
* @brief Overflow-safe clamped addition: returns value + delta bounded to [minValue, maxValue].
|
* @brief Overflow-safe clamped addition: returns value + delta bounded to [minValue, maxValue].
|
||||||
*
|
*
|
||||||
* Uses a 64-bit intermediate so the addition itself cannot overflow int. Shared by the
|
* Uses a 64-bit intermediate so the addition cannot overflow int. Shared by the counter
|
||||||
* counter arithmetic in Server_Card and Server_Counter so both stay in sync.
|
* arithmetic in Server_Card, Server_Counter, and PlayerActions.
|
||||||
*
|
*
|
||||||
* @note Requires minValue <= maxValue. Bounds come from trusted compile-time call sites;
|
* @note Requires minValue <= maxValue. Bounds come from trusted compile-time call sites;
|
||||||
* qBound() asserts this internally in debug builds.
|
* qBound() asserts this internally in debug builds.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue