Upozornění kompilátoru (úroveň 4) C4754
Pravidla převodu pro aritmetické operace v porovnání znamenají, že jednu větev nelze spustit.
Upozornění C4754 je vydáno, protože výsledek porovnání je vždy stejný. To znamená, že jedna z větví podmínky se nikdy nespustí, pravděpodobně proto, že přidružený celočíselné výraz je nesprávný. Tato chyba kódu se často vyskytuje v nesprávných kontrolách přetečení celého čísla v 64bitových architekturách.
Celočíselná pravidla převodu jsou složitá a existuje mnoho drobných nástrah. Jako alternativu k opravě každého upozornění C4754 můžete kód aktualizovat tak, aby používal knihovnu SafeInt.
Příklady
Tato ukázka vygeneruje C4754:
// C4754a.cpp
// Compile with: /W4 /c
#include "errno.h"
int sum_overflow(unsigned long a, unsigned long b)
{
unsigned long long x = a + b; // C4754
if (x > 0xFFFFFFFF)
{
// never executes!
return EOVERFLOW;
}
return 0;
}
Přidání a + b
může způsobit aritmetický přetečení před tím, než se výsledek přepíná na 64bitovou hodnotu a přiřadí se k 64bitové proměnné x
. To znamená, že kontrola x
je redundantní a nikdy nezachytí přetečení. V tomto případě kompilátor vygeneruje toto upozornění:
Warning C4754: Conversion rules for arithmetic operations in the comparison at C4754a.cpp (7) mean that one branch cannot be executed. Cast '(a + ...)' to 'ULONG64' (or similar type of 8 bytes).
Pokud chcete upozornění odstranit, můžete změnit příkaz přiřazení tak, aby přetypoval operandy na hodnoty 8 bajtů:
// Casting one operand is sufficient to force all the operands in
// the addition be upcast according to C/C++ conversion rules, but
// casting both is clearer.
unsigned long long x =
(unsigned long long)a + (unsigned long long)b;
Další ukázka také vygeneruje C4754.
// C4754b.cpp
// Compile with: /W4 /c
#include "errno.h"
int wrap_overflow(unsigned long a)
{
if (a + sizeof(unsigned long) < a) // C4754
{
// never executes!
return EOVERFLOW;
}
return 0;
}
Operátor sizeof()
vrátí size_t
hodnotu , jejíž velikost je závislá na architektuře. Ukázkový kód funguje na 32bitových architekturách, kde size_t
je 32bitový typ. U 64bitových size_t
architektur je však 64bitový typ. Pravidla převodu pro celá čísla znamenají, že a
je v výrazu a + b < a
upcast na 64bitovou hodnotu, jako by byla zapsána (size_t)a + (size_t)b < (size_t)a
. Pokud a
a b
jsou 32bitová celá čísla, 64bitová operace sčítání nikdy nemůže přetékat a omezení nikdy neudrží. V důsledku toho kód nikdy nezjistí celočíselnou podmínku přetečení v 64bitových architekturách. Tento příklad způsobí, že kompilátor vygeneruje toto upozornění:
Warning C4754: Conversion rules for arithmetic operations in the comparison at C4754b.cpp (7) mean that one branch cannot be executed. Cast '4' to 'ULONG' (or similar type of 4 bytes).
Všimněte si, že zpráva upozornění explicitně uvádí hodnotu konstanty 4 místo původního zdrojového řetězce – v době, kdy analýza upozornění narazí na off-endový kód, sizeof(unsigned long)
již byla převedena na konstantu. Proto možná budete muset zjistit, který výraz ve zdrojovém kódu je přidružen k konstantní hodnotě ve zprávě upozornění. Nejběžnějšími zdroji kódu vyřešené na konstanty v upozorněních C4754 jsou výrazy jako sizeof(TYPE)
a strlen(szConstantString)
.
V tomto případě by pevný kód vypadal takto:
// Casting the result of sizeof() to unsigned long ensures
// that all the addition operands are 32-bit, so any overflow
// is detected by the check.
if (a + (unsigned long)sizeof(unsigned long) < a)
Poznámka: Číslo řádku uvedené v upozorněních kompilátoru je poslední řádek příkazu. V upozornění na složitý podmíněný příkaz, který je rozložen na více řádků, může být řádek s kódem vad několik řádků před oznamované čárou. Příklad:
unsigned long a;
if (a + sizeof(unsigned long) < a || // incorrect check
condition1() ||
a == 0) { // C4754 warning reported on this line
// never executes!
return INVALID_PARAMETER;
}