debuggers.hg
changeset 14627:d4ddaff75afd
hvm: Fix undefined bit shifting in mmio emulation path
In functions set_eflags_* (xen/arch/x86/hvm/io.c), if the first
argument "size" equals sizeof(long), the following code will produce
unintended and invalid result:
unsigned long mask = (1 << (8 * size)) - 1;
In ANSI C, if the shift amount is greater or equal to the width of the
data type, the result is undefined. Specifically on x86, a bit mask is
applied to the shift amount, so that more significant bits are
ignored. So the above expression results 0x0 instead of the intended
~0UL.
This patch fixes this issue. Because size=0 is not a valid parameter,
rewriting the code using right shift avoids an additional condition
check.
Signed-off-by: Qing He <qing.he@intel.com>
In functions set_eflags_* (xen/arch/x86/hvm/io.c), if the first
argument "size" equals sizeof(long), the following code will produce
unintended and invalid result:
unsigned long mask = (1 << (8 * size)) - 1;
In ANSI C, if the shift amount is greater or equal to the width of the
data type, the result is undefined. Specifically on x86, a bit mask is
applied to the shift amount, so that more significant bits are
ignored. So the above expression results 0x0 instead of the intended
~0UL.
This patch fixes this issue. Because size=0 is not a valid parameter,
rewriting the code using right shift avoids an additional condition
check.
Signed-off-by: Qing He <qing.he@intel.com>
author | kfraser@localhost.localdomain |
---|---|
date | Tue Mar 27 16:56:20 2007 +0100 (2007-03-27) |
parents | 681ed46676a6 |
children | c1bfe329f7ff |
files | xen/arch/x86/hvm/io.c |
line diff
1.1 --- a/xen/arch/x86/hvm/io.c Tue Mar 27 16:45:37 2007 +0100 1.2 +++ b/xen/arch/x86/hvm/io.c Tue Mar 27 16:56:20 2007 +0100 1.3 @@ -292,7 +292,11 @@ extern long get_reg_value(int size, int 1.4 static inline void set_eflags_CF(int size, unsigned long v1, 1.5 unsigned long v2, struct cpu_user_regs *regs) 1.6 { 1.7 - unsigned long mask = (1 << (8 * size)) - 1; 1.8 + unsigned long mask; 1.9 + 1.10 + ASSERT((size <= sizeof(mask)) && (size > 0)); 1.11 + 1.12 + mask = ~0UL >> (8 * (sizeof(mask) - size)); 1.13 1.14 if ((v1 & mask) > (v2 & mask)) 1.15 regs->eflags |= X86_EFLAGS_CF; 1.16 @@ -303,7 +307,13 @@ static inline void set_eflags_CF(int siz 1.17 static inline void set_eflags_OF(int size, unsigned long v1, 1.18 unsigned long v2, unsigned long v3, struct cpu_user_regs *regs) 1.19 { 1.20 - if ((v3 ^ v2) & (v3 ^ v1) & (1 << ((8 * size) - 1))) 1.21 + unsigned long mask; 1.22 + 1.23 + ASSERT((size <= sizeof(mask)) && (size > 0)); 1.24 + 1.25 + mask = ~0UL >> (8 * (sizeof(mask) - size)); 1.26 + 1.27 + if ((v3 ^ v2) & (v3 ^ v1) & mask) 1.28 regs->eflags |= X86_EFLAGS_OF; 1.29 } 1.30 1.31 @@ -317,7 +327,11 @@ static inline void set_eflags_AF(int siz 1.32 static inline void set_eflags_ZF(int size, unsigned long v1, 1.33 struct cpu_user_regs *regs) 1.34 { 1.35 - unsigned long mask = (1 << (8 * size)) - 1; 1.36 + unsigned long mask; 1.37 + 1.38 + ASSERT((size <= sizeof(mask)) && (size > 0)); 1.39 + 1.40 + mask = ~0UL >> (8 * (sizeof(mask) - size)); 1.41 1.42 if ((v1 & mask) == 0) 1.43 regs->eflags |= X86_EFLAGS_ZF; 1.44 @@ -326,7 +340,13 @@ static inline void set_eflags_ZF(int siz 1.45 static inline void set_eflags_SF(int size, unsigned long v1, 1.46 struct cpu_user_regs *regs) 1.47 { 1.48 - if (v1 & (1 << ((8 * size) - 1))) 1.49 + unsigned long mask; 1.50 + 1.51 + ASSERT((size <= sizeof(mask)) && (size > 0)); 1.52 + 1.53 + mask = ~0UL >> (8 * (sizeof(mask) - size)); 1.54 + 1.55 + if (v1 & mask) 1.56 regs->eflags |= X86_EFLAGS_SF; 1.57 } 1.58