Bug 587128

Summary: Apparent gcc 4.4.3 miscompilation
Product: [Fedora] Fedora Reporter: Sam Varshavchik <mrsam>
Component: gccAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: low    
Version: 12CC: jakub
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2010-04-29 09:02:34 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Sam Varshavchik 2010-04-29 01:34:19 UTC
Description of problem:

Looks like gcc might be miscompiling code that uses the XOR hack of swapping two integer values.

Version-Release number of selected component (if applicable):

gcc-4.4.3-4.fc12.i686

How reproducible:

#include <iostream>

struct A {

	size_t x1, y1, x2, y2;

	void foo(size_t &row1, size_t &row2,
		 size_t &pos1, size_t &pos2);
};

void A::foo(size_t &row1, size_t &row2,
	    size_t &pos1, size_t &pos2)
{
	row1=y1;
	row2=y2;
	pos1=x1;
	pos2=x2;

	if (row2 < row1 || (row2 == row1 && pos2 < pos1))
	{
                // Swap the coordinate pairs

		row1 ^= row2 ^= row1 ^= row2;
		pos1 ^= pos2 ^= pos1 ^= pos2;
	}
}

int main()
{
	A aa;

	aa.y1=5;
	aa.x1=1;
	aa.y2=0;
	aa.x2=2;

	size_t row1, row2, col1, col2;

	aa.foo(row1, row2, col1, col2);

	std::cout << "row1=" << row1 << ", col1=" << col1
		  << ", row2=" << row2 << ", col2=" << col2 << std::endl;

	return (0);
}

Steps to Reproduce:
1. Compile the above code: g++ -o /tmp/t /tmp/t.C
2.
3.
  
Actual results:

$ /tmp/t
row1=0, col1=0, row2=5, col2=1

Expected results:

$ /tmp/t
row1=0, col1=2, row2=5, col2=1

Additional info:

The sequence "a ^= b ^= a ^= b" is a hack which essentially swaps the values of a and b. Example:

Starting values: a=1, b=2

After a ^= b:  a=3, b=2

After b ^= a ^= b: a=3, b=1

After a ^= b ^= a ^= b: a=2, b=1

The above example is a snippet of code that takes a pair of two-dimensional (x, y) coordinates, and returns the "lowest" (x, y) pair and the highest pair.

Looks like a struct/class, and a function call passing return values by reference are a necessary ingredient to trigger the miscompilation.

Comment 1 Jakub Jelinek 2010-04-29 09:02:34 UTC
row1 ^= row2 ^= row1 ^= row2;
has undefined behavior in both C and C++, and even -Wsequence-point (part of -Wall) warns about it.