Hi , the following program segfault with g++3.3 , works with g++2.95 why ????

D

devesh.agrawal

Hi , this program does a segfault in g++3.2 onwards , works with
g++2.95 ,
Any ideas are welcome , basically there is this instruction when
compiled with -S option , call *%eax , where the one with 2.95 goes on
to execude the given machine code , whereas the one compiled in g++3.2
segfaults.
Also if you feel , this is not an appropriate group to post this , I
would be obliged if you could pardon me for the mistake and guide me to
a better group.

#include <iostream>
#include <string>
using namespace std;
typedef long (*fptr) (long, long);
void
write (string & str)
{
str += (char) 0x55;//push %ebp
str += (char) 0x8B;//mov %esp,%ebp
str += (char) 0xEC;
str += (char) 0x8B;//mov 8(%ebp),%eax
str += (char) 0x45;
str += (char) 0x08;
str += (char) 0x03;//add 12(%ebp),%eax
str += (char) 0x45;
str += (char) 0x0C;
str += (char) 0x5D;//pop %ebp
str += (char) 0xC3;//ret
}

main ()
{
fptr Func;
unsigned int val1, val2, retVal;
string str;
write (str);
Func = (fptr) str.c_str ();
val1 = 123456;
val2 = 654321;
retVal = Func (val1, val2);
cout << "Ans: " << retVal << endl;
return 0;
}

PS : CC the replies to me would be appreciated.
 
S

Sharad Kala


The "implicit int" rule of C is no longer supported in C++.
{
fptr Func;
unsigned int val1, val2, retVal;
string str;
write (str);
Func = (fptr) str.c_str ();

What kind of conversion is this ? You are trying to convert a const char *
to fptr!
val1 = 123456;
val2 = 654321;
retVal = Func (val1, val2);
cout << "Ans: " << retVal << endl;
return 0;
}

PS : CC the replies to me would be appreciated.

Post here, read here.

Sharad
 
A

Anirudh

Hi , this program does a segfault in g++3.2 onwards , works with
g++2.95 ,
Any ideas are welcome , basically there is this instruction when
compiled with -S option , call *%eax , where the one with 2.95 goes on
to execude the given machine code , whereas the one compiled in g++3.2
segfaults.
Also if you feel , this is not an appropriate group to post this , I
would be obliged if you could pardon me for the mistake and guide me to
a better group.

#include <iostream>
#include <string>
using namespace std;
typedef long (*fptr) (long, long);

I wrote a simple sum function:
long sum(long a, long b)
{
return a + b;
}

The disassembly of this produces the exact same code for
g++2.95. But for 3.3, there are slight differences.
void
write (string & str)
{
str += (char) 0x55;//push %ebp
str += (char) 0x8B;//mov %esp,%ebp
str += (char) 0xEC;
str += (char) 0x8B;//mov 8(%ebp),%eax
str += (char) 0x45;
str += (char) 0x08;
str += (char) 0x03;//add 12(%ebp),%eax
str += (char) 0x45;
str += (char) 0x0C;
str += (char) 0x5D;//pop %ebp

g++ 3.3 puts a 'leave' instruction instead of 'pop ebp'. But
leave does pretty much the same thing, I guess. But modifying
the above to put a leave doesn't seem to work either.
str += (char) 0xC3;//ret

There's also a 'nop' added to the function assembly code
after the return (in 3.3). Could the segfault be because of
alignment problems?
}

main ()
{
fptr Func;
unsigned int val1, val2, retVal;
string str;
write (str);
Func = (fptr) str.c_str ();

I'm relatively a newbie, but I read somewhere that assigning a data item
to a function pointer like the above invokes undefined behaviour. Could
that be the reason that compilers behave differently?
val1 = 123456;
val2 = 654321;
retVal = Func (val1, val2);
cout << "Ans: " << retVal << endl;
return 0;
}

PS : CC the replies to me would be appreciated.

Basically, I'm stumped too. Maybe someone else can find out where I
didn't think hard enough.


-- Anirudh
 
A

Anirudh

Anirudh said:
I wrote a simple sum function:
long sum(long a, long b)
{
return a + b;
}

The disassembly of this produces the exact same code for
g++2.95. But for 3.3, there are slight differences.

Sorry, the 'long' should be replaced with 'int' to produce
the code below. Otherwise, everything turns out to be pushl,
popl etc...
g++ 3.3 puts a 'leave' instruction instead of 'pop ebp'. But
leave does pretty much the same thing, I guess. But modifying
the above to put a leave doesn't seem to work either.


There's also a 'nop' added to the function assembly code
after the return (in 3.3). Could the segfault be because of
alignment problems?


I'm relatively a newbie, but I read somewhere that assigning a data item
to a function pointer like the above invokes undefined behaviour. Could
that be the reason that compilers behave differently?


Basically, I'm stumped too. Maybe someone else can find out where I
didn't think hard enough.


-- Anirudh

-- Anirudh
 
M

Michael Kurz

main ()
{
fptr Func;
unsigned int val1, val2, retVal;
string str;
write (str);
Func = (fptr) str.c_str ();
val1 = 123456;
val2 = 654321;
retVal = Func (val1, val2);
cout << "Ans: " << retVal << endl;
return 0;
}

PS : CC the replies to me would be appreciated.

Which OS are you working on?
=> are you allowd to execut code within the address space your code is in?
(In Windows: VirtualProtect(..) )
perhapes try a simple ret. I tried on my debian linux so I guess its a
problem with the memory permissions, or the segment descriptors. Im not so
familiy with this stuff on linux (I only used to work with it on windows).

But when I placed the code on the stack it worked. Your sample places the
code on the heap (new) as this is the function std::string::c_str() is
probably using. If you would use data on the stack or even global it should
work.


Regards
Michael

<snip>


char gByte = 0xC3;

int main(){
// Failed as I guess the no execution on the heaps address space. (even
the segment descriptors could be different)
std::string fct_code = "0xC3";
LPFN_Func Func = (LPFN_Func)fct_code.c_str();
Func();

// Worked on my machine P4, gcc 3.3.4 debian
char byte = 0xC3;
LPFN_Func Func2 = (LPFN_Func)&byte;
Func2();

// Worked on my machine P4, gcc 3.3.4 debian
LPFN_Func Func3 = (LPFN_Func)&gByte;
Func3();

}




</snip>
 
J

Jack Klein

Hi , this program does a segfault in g++3.2 onwards , works with
g++2.95 ,
Any ideas are welcome , basically there is this instruction when
compiled with -S option , call *%eax , where the one with 2.95 goes on
to execude the given machine code , whereas the one compiled in g++3.2
segfaults.
Also if you feel , this is not an appropriate group to post this , I
would be obliged if you could pardon me for the mistake and guide me to
a better group.

#include <iostream>
#include <string>
using namespace std;
typedef long (*fptr) (long, long);
void
write (string & str)
{
str += (char) 0x55;//push %ebp
str += (char) 0x8B;//mov %esp,%ebp
str += (char) 0xEC;
str += (char) 0x8B;//mov 8(%ebp),%eax
str += (char) 0x45;
str += (char) 0x08;
str += (char) 0x03;//add 12(%ebp),%eax
str += (char) 0x45;
str += (char) 0x0C;
str += (char) 0x5D;//pop %ebp
str += (char) 0xC3;//ret
}

main ()
{
fptr Func;
unsigned int val1, val2, retVal;
string str;
write (str);
Func = (fptr) str.c_str ();

[snip]

This line is completely illegal in either C or C++. There is
absolutely no conversion defined at all between pointers to functions
and pointers to objects.

The behavior of this code is completely undefined. Whatever happens
once you execute the last line above is not a matter for the C++
language at all. It does not specify, nor does it care.

Either stop writing such nonsense, or take it to a compiler specific
support group. It is not a language issue because you have violated
the rules of the language.
 
M

Michael Kurz

Jack Klein said:
main ()
{
fptr Func;
unsigned int val1, val2, retVal;
string str;
write (str);
Func = (fptr) str.c_str ();

[snip]


Either stop writing such nonsense, or take it to a compiler specific
support group. It is not a language issue because you have violated
the rules of the language.

I would say its definitely not nonsense, and even if so, telling someone
with these words sounds not very polite to me.
IMHO it's quite similar to a downcast or all other constructs where the
compiler does not have the type information anymore and its completely in
the hands
of the programmer to know what he is doing. I can agree that such situations
should be avoided if possible but if not, I'd say it always was a strength
of C to allow
such things and so it is in C++.
 

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top