运营商优先级和自动升级(避免溢出)

时间:2015-05-18 23:20:20

标签: c casting integer-promotion

以字节为单位查找某些数据的大小是一种常见的操作。

受挫的例子:

pa-pocb (master)$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 62 vars */]) = 0
brk(0)                                  = 0xf39000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc88f98f000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
stat("/opt/intel/composer_xe_2013_sp1.3.174/compiler/lib/intel64", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/opt/intel/mic/coi/host-linux-release/lib", {st_mode=S_IFDIR|0755, st_size=50, ...}) = 0
stat("/opt/intel/composer_xe_2013_sp1.3.174/ipp/lib/intel64", {st_mode=S_IFDIR|0755, st_size=8192, ...}) = 0
stat("/opt/intel/composer_xe_2013_sp1.3.174/mkl/lib/intel64", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

stat("/opt/intel/composer_xe_2013_sp1.3.174/tbb/lib/intel64/gcc4.4", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=35612, ...}) = 0
mmap(NULL, 35612, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fc88f986000
close(3)                                = 0
open("/lib64/libexpect.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\222\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=192632, ...}) = 0
mmap(NULL, 2298320, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc88f53d000
mprotect(0x7fc88f569000, 2093056, PROT_NONE) = 0
mmap(0x7fc88f768000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2b000) = 0x7fc88f768000
mmap(0x7fc88f76b000, 12752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc88f76b000
close(3)                                = 0
open("/lib64/libtcl8.5.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P:\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0555, st_size=1229240, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc88f985000
mmap(NULL, 3293016, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc88f219000
mprotect(0x7fc88f332000, 2093056, PROT_NONE) = 0
mmap(0x7fc88f531000, 49152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x118000) = 0x7fc88f531000
close(3)                                = 0
open("/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260T\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1141552, ...}) = 0
mmap(NULL, 3150168, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc88ef17000
mprotect(0x7fc88f018000, 2093056, PROT_NONE) = 0
mmap(0x7fc88f217000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x100000) = 0x7fc88f217000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2107760, ...}) = 0
mmap(NULL, 3932736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc88eb56000
mprotect(0x7fc88ed0c000, 2097152, PROT_NONE) = 0
mmap(0x7fc88ef0c000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7fc88ef0c000
mmap(0x7fc88ef12000, 16960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc88ef12000
close(3)                                = 0
open("/lib64/libutil.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\17\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=14608, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc88f984000
mmap(NULL, 2105616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc88e953000
mprotect(0x7fc88e955000, 2093056, PROT_NONE) = 0
mmap(0x7fc88eb54000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7fc88eb54000
close(3)                                = 0
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\16\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=19512, ...}) = 0
mmap(NULL, 2109744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc88e74f000
mprotect(0x7fc88e752000, 2093056, PROT_NONE) = 0
mmap(0x7fc88e951000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7fc88e951000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc88f983000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc88f981000
arch_prctl(ARCH_SET_FS, 0x7fc88f981740) = 0
mprotect(0x7fc88ef0c000, 16384, PROT_READ) = 0
mprotect(0x7fc88e951000, 4096, PROT_READ) = 0
mprotect(0x7fc88eb54000, 4096, PROT_READ) = 0
mprotect(0x7fc88f217000, 4096, PROT_READ) = 0
mprotect(0x7fc88f531000, 20480, PROT_READ) = 0
mprotect(0x7fc88f768000, 4096, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7fc88f990000, 4096, PROT_READ) = 0
munmap(0x7fc88f986000, 35612)           = 0
brk(0)                                  = 0xf39000
brk(0xf5a000)                           = 0xf5a000
brk(0)                                  = 0xf5a000
open("/dev/tty", O_RDWR)                = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(3, TIOCGWINSZ, {ws_row=62, ws_col=212, ws_xpixel=1696, ws_ypixel=930}) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x410} ---
+++ killed by SIGSEGV +++
Segmentation fault

这里明显的错误是int会溢出(例如23171x23171 RGBA字节缓冲区)。

3个或更多值相乘时的促销规则是什么?
(将一对值相乘很简单)

我们可以安全地播放它:

char *buffer_size(int x, int y, int chan_count, int chan_size)
{
    size_t buf_size = x * y * chan_count * chan_size;  /* <-- this may overflow! */
    char *buf = malloc(buf_size);
    return buf;
}

另一种选择是在括号中添加以确保乘法和...的顺序。促销是可预测的(并且对之间的自动促销按预期工作)......

size_t buf_size = (size_t)x * (size_t)y * (size_t)chan_count * (size_t)chan_size;

......哪个有效,但我的问题是。

是否存在确定性方法来乘以3个或更多值以确保它们会自动升级?
(以避免溢出)

或者这是未定义的行为吗?

备注...

  • size_t buf_size = ((((size_t)x * y) * chan_count) * chan_size; 处使用 阻止溢出,只是防止溢出该类型的最大值。
  • 在给出的示例中,将参数设置为size_t也是有意义的,但这不是这个问题的重点。

0 个答案:

没有答案