Bug 29582 - Parameter pushed to stack too soon
Summary: Parameter pushed to stack too soon
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.3.5
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-10-24 15:56 UTC by Oleh Derevenko
Modified: 2006-10-31 00:01 UTC (History)
2 users (show)

See Also:
Host: x86
Target: x86
Build: x86
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Compilable testcase (400 bytes, application/octet-stream)
2006-10-30 08:33 UTC, Oleh Derevenko
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Oleh Derevenko 2006-10-24 15:56:35 UTC
Given class COtherClass having methods
class COtherClass
{
...
	inline COtherClass(unsigned int uiParam1, const char *pszParam2, const char *pszParam3, unsigned long ulParam4, const char *pszParam5)
	{...}
	~COtherClass();
	COtherClass &Method1();
	COtherClass &Method2(unsigned long long &ullParam);
	COtherClass &operator ()(const char *pszParam1, const void *pvParam2);
	COtherClass &operator ()(const char *pszParam1, unsigned long long ullParam2) { ... }
};

For code 
struct CHostClass
{
public:
	unsigned long long m_ullProblemField;
	const void	*m_pvPointerField;
	const char	*m_szSzField;
	
	~CHostClass()
	{
		COtherClass(5, m_szSzField, NULL, 0, "ImmString1").Method1().Method2(m_ullProblemField)("ImmString2", m_pvPointerField)("ImmString3", m_ullProblemField);
	}
};

GCC generated the following assembler text (debug build)
mov    0x8(%ebp),%eax // CHostClass::this
pushl  0x4(%eax) // HI(CHostClass::m_ullProblemField)
pushl  (%eax) // LO(CHostClass::m_ullProblemField)
push   $0x81f10f9 // "ImmString3"
sub    $0x8,%esp
mov    0x8(%ebp),%eax // CHostClass::this
pushl  0x8(%eax) // CHostClass::m_pvPointerField
push   $0x81f0e3a // "ImmString2"
sub    $0xc,%esp
pushl  0x8(%ebp) // CHostClass::this <=> offset CHostClass::m_ullProblemField
sub    $0xc,%esp
push   $0x81f1104 // "ImmString1"
push   $0x0 // 0
push   $0x0 // NULL
mov    0x8(%ebp),%eax // CHostClass::this
pushl  0xc(%eax) // CHostClass::m_szSzField
push   $0x5 // 5
lea    0xfffff4e8(%ebp),%eax // storage for COtherClass instance
push   %eax
call   0x804e61c // COtherClass::COtherClass constructor
add    $0x24,%esp // 6*4 params + 12 reserve made with "sub $0xc,%esp"
lea    0xfffff4e8(%ebp),%eax // instance of COtherClass
push   %eax
call   0x818e68e // COtherClass::Method1
add    $0x4,%esp // 1 param
push   %eax // instance of COtherClass
call   0x8190384 // COtherClass::Method2
add    $0x14,%esp // 2*4 params + 12 reserve made with "sub $0xc,%esp"
push   %eax // instance of COtherClass
call   0x818e85c // COtherClass::operator()(const char *, const void *)
add    $0x14,%esp // 3*4 params + 8 reserve made with "sub $0x8,%esp"
push   %eax // instance of COtherClass
call   0x804f322 // COtherClass::operator()(const char *, unsigned long long)
add    $0x10,%esp // 2*4 + 1*8 params
sub    $0xc,%esp
lea    0xfffff4e8(%ebp),%eax // instance of COtherClass
push   %eax
call   0x818e610 // COtherClass::~COtherClass
add    $0x10,%esp // 1*4 params + 12 reserve made with "sub $0xc,%esp"

The problem is that the value of m_ullProblemField is pushed to stack at the very beginning of code while it is modified later during invocation of COtherClass::Method2. COtherClass::operator (const char *, unsigned long long) should receive modified value of field but it receives initial one.
Comment 1 Andreas Schwab 2006-10-24 16:02:57 UTC
The evaluation order of function arguments is not specified.  If you depend on side effects to be carried out at a specific point you must make sure there is a sequence point at the appropriate place.
Comment 2 Oleh Derevenko 2006-10-24 16:09:50 UTC
(In reply to comment #1)
> The evaluation order of function arguments is not specified.  If you depend on
> side effects to be carried out at a specific point you must make sure there is
> a sequence point at the appropriate place.

These are not the arguments of a single function. Given example is the sequence of method invocations for a class instance. Modification of lvalue occurs in 2nd method invocation and it is supposed to be passed to 4th method invocation.
Comment 3 Andrew Pinski 2006-10-29 20:40:46 UTC
Do you have a testcase that actually compiles?
Comment 4 Oleh Derevenko 2006-10-30 08:33:30 UTC
Created attachment 12509 [details]
Compilable testcase
Comment 5 Wolfgang Bangerth 2006-10-31 00:01:15 UTC
(In reply to comment #0)
>                 COtherClass(5, m_szSzField, NULL, 0,
> "ImmString1").Method1().Method2(m_ullProblemField)("ImmString2",
> m_pvPointerField)("ImmString3", m_ullProblemField);
> [...]
> The problem is that the value of m_ullProblemField is pushed to stack at the
> very beginning of code while it is modified later during invocation of
> COtherClass::Method2. COtherClass::operator (const char *, unsigned long long)
> should receive modified value of field but it receives initial one.

No. The order of evaluation of your sequence of function calls is 
unspecified. There is no sequence point within your chain of calls, and
therefore the compiler is free to select whatever order for evaluating
the arguments of all these calls.

W.