Error in i386 cmpxchg instruction emulation

Bug #569760 reported by Andreas Gustafsson
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
QEMU
Fix Released
Undecided
Unassigned

Bug Description

As reported in

  http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=42158

programs using pthreads and fork() under NetBSD/i386 hang when the
NetBSD system is run within qemu.

This problem affects every version of qemu I have tested, including 0.12.3.

I have now tracked down the cause of the problem to a bug in qemu's
emulation of the cmpxchg instruction. Quoting the above bug report:

  In a physical i386 CPU, the cmpxchg instruction performs a comparison
  and read-modify-write memory cycle. In the case where the comparison
  outcome is "unequal", the read-modify-write cycle is an effective
  no-op, writing back the same value that was read, and the value of the
  source operand is loaded into the accumulator. Qemu attempts to
  emulate this behavior including the redundant memory write.

  To be precise, qemu first loads the accumulator and then does the
  redundant memory write. If a page fault occurs during the write, the
  cmpxchg instruction will be restarted after handling the page fault,
  but because the accumulator has already been changed, the comparison
  will now incorrectly yield a result of "equal", causing the memory
  write to write the value from the source operand instead of re-writing
  the original memory contents.

  I assume fork() triggers the bug because it write protects pages to
  implement copy-on-write, thereby producing a situation where the read
  part of the cmpxchg read-modify-write cycle succeeds but the write
  part causes a page fault.

  Patching qemu to only change the accumulator after performing the
  redundant write fixes the problem for me.

I will attach a patch against qemu 0.12.3 shortly.

Revision history for this message
Andreas Gustafsson (gson) wrote :
Changed in qemu:
status: New → Fix Committed
Peter Maydell (pmaydell)
Changed in qemu:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.