Visual C++ 6.0 - 可能的转换数据丢失(警告 C4244)
Visual C++ 6.0 - Possible Conversion Loss of Data (Warning C4244)
我使用的是相当老的编译器,我相信编译器在其警告诊断中犯了一点错误。
typedef unsigned char uint8_t; // 8-bit byte
typedef unsigned int uint32_t; // 32-bit word (change to "long" for 16-bit machines)
typedef struct _sha256_ctx_t
{
uint8_t data[64];
uint32_t data_len;
unsigned __int64 bit_len; // unsigned long long
uint32_t state[8];
} sha256_ctx_t;
void crypto_sha256_final(sha256_ctx_t *ctx, uint8_t *digest)
{
uint32_t i;
i = ctx->data_len;
// Append to the padding the total message's length in bits and transform.
ctx->bit_len += ctx->data_len * 8;
ctx->data[63] = ctx->bit_len; // LINE 156 IS HERE!
ctx->data[62] = ctx->bit_len >> 8;
ctx->data[61] = ctx->bit_len >> 16;
ctx->data[60] = ctx->bit_len >> 24;
ctx->data[59] = ctx->bit_len >> 32;
ctx->data[58] = ctx->bit_len >> 40;
ctx->data[57] = ctx->bit_len >> 48;
ctx->data[56] = ctx->bit_len >> 56; // LINE 163 IS HERE!
local_sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output digest.
for (i = 0; i < 4; ++i) {
digest[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
digest[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
digest[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
digest[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
digest[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
digest[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
digest[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
digest[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
该代码导致此错误(从第 156 行到第 163 行):
SHA256.cpp(156) : warning C4244: '=' : conversion from 'unsigned __int64' to 'unsigned char', possible loss of data
我猜这个旧编译器没有意识到将它与 0xFF 相加会将结果缩小到一个字节。有人对如何绕过错误警告有建议吗?
在这种情况下,编译器没有任何问题
ctx->data[63] = ctx->bit_len; // LINE 156 IS HERE!
ctx->data[62] = ctx->bit_len >> 8;
ctx->data[61] = ctx->bit_len >> 16;
ctx->data[60] = ctx->bit_len >> 24;
ctx->data[59] = ctx->bit_len >> 32;
ctx->data[58] = ctx->bit_len >> 40;
ctx->data[57] = ctx->bit_len >> 48;
ctx->data[56] = ctx->bit_len >> 56; // LINE 163 IS HERE!
ctx->bit_len
是 64 位类型,因此显然将其存储到 uint8_t
中是行不通的。在 digest[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
中的那些行中没有使用 0xFF
的掩码。唯一缺少分析的情况是 ctx->data[56] = ctx->bit_len >> 56
,因为结果符合 uint8_t
。要获得 LSB,您需要进行显式转换,以便编译器知道您在做什么
ctx->data[62] = uint8_t(ctx->bit_len >> 8);
也就是说,没有必要像那样手动复制,只需使用memcpy
和ntohll
。代码不好,使用古老的编译器更糟。现在有很多很好的加密库使用适当的 SIMD 和多线程,比如 OpenSSL
编译器可以足够聪明地检查算术表达式的可能范围(在明显的情况下),如果不检查,该编译器发出警告是非常正确的。这确实是由较新版本的编译器以不同方式处理的。
试试这个治疗方法:将分配的表达式转换为 char
。
我使用的是相当老的编译器,我相信编译器在其警告诊断中犯了一点错误。
typedef unsigned char uint8_t; // 8-bit byte
typedef unsigned int uint32_t; // 32-bit word (change to "long" for 16-bit machines)
typedef struct _sha256_ctx_t
{
uint8_t data[64];
uint32_t data_len;
unsigned __int64 bit_len; // unsigned long long
uint32_t state[8];
} sha256_ctx_t;
void crypto_sha256_final(sha256_ctx_t *ctx, uint8_t *digest)
{
uint32_t i;
i = ctx->data_len;
// Append to the padding the total message's length in bits and transform.
ctx->bit_len += ctx->data_len * 8;
ctx->data[63] = ctx->bit_len; // LINE 156 IS HERE!
ctx->data[62] = ctx->bit_len >> 8;
ctx->data[61] = ctx->bit_len >> 16;
ctx->data[60] = ctx->bit_len >> 24;
ctx->data[59] = ctx->bit_len >> 32;
ctx->data[58] = ctx->bit_len >> 40;
ctx->data[57] = ctx->bit_len >> 48;
ctx->data[56] = ctx->bit_len >> 56; // LINE 163 IS HERE!
local_sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output digest.
for (i = 0; i < 4; ++i) {
digest[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
digest[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
digest[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
digest[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
digest[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
digest[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
digest[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
digest[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
该代码导致此错误(从第 156 行到第 163 行):
SHA256.cpp(156) : warning C4244: '=' : conversion from 'unsigned __int64' to 'unsigned char', possible loss of data
我猜这个旧编译器没有意识到将它与 0xFF 相加会将结果缩小到一个字节。有人对如何绕过错误警告有建议吗?
在这种情况下,编译器没有任何问题
ctx->data[63] = ctx->bit_len; // LINE 156 IS HERE!
ctx->data[62] = ctx->bit_len >> 8;
ctx->data[61] = ctx->bit_len >> 16;
ctx->data[60] = ctx->bit_len >> 24;
ctx->data[59] = ctx->bit_len >> 32;
ctx->data[58] = ctx->bit_len >> 40;
ctx->data[57] = ctx->bit_len >> 48;
ctx->data[56] = ctx->bit_len >> 56; // LINE 163 IS HERE!
ctx->bit_len
是 64 位类型,因此显然将其存储到 uint8_t
中是行不通的。在 digest[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
中的那些行中没有使用 0xFF
的掩码。唯一缺少分析的情况是 ctx->data[56] = ctx->bit_len >> 56
,因为结果符合 uint8_t
。要获得 LSB,您需要进行显式转换,以便编译器知道您在做什么
ctx->data[62] = uint8_t(ctx->bit_len >> 8);
也就是说,没有必要像那样手动复制,只需使用memcpy
和ntohll
。代码不好,使用古老的编译器更糟。现在有很多很好的加密库使用适当的 SIMD 和多线程,比如 OpenSSL
编译器可以足够聪明地检查算术表达式的可能范围(在明显的情况下),如果不检查,该编译器发出警告是非常正确的。这确实是由较新版本的编译器以不同方式处理的。
试试这个治疗方法:将分配的表达式转换为 char
。