Weird behaviour of compiler

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • K Siddharth
    New Member
    • Dec 2015
    • 8

    #1

    Weird behaviour of compiler

    I was working on a project in c++,which involved managing accounts.Here is an extract of source code of project

    1.logging in

    Code:
    user user::login(short int pur)
    {
    	clrscr();
    	fstream f("users.dat",ios::in|ios::out|ios::binary);
    	user u[10];
    	int i=0;
    	while(f.read((char*)&u[i],sizeof(user)))
    		i++;
    	f.close();
    	cout<<"Enter user name\n";
    	char n[30];
    	gets(n);
    	int pos=search(u,n,i);
    	int chk=0;
    	if(pos==-1)
    	{
    		cout<<"Sorry user not found\n";
    		return fail();
    	}
    	cout<<"Enter password\n";
    	gets(n);
    	int ver=verify_password(u[pos],n);
    	if(ver==0)
    	{
    		if(pur==0)
    		{
    			cout<<"Access granted\n";
    			getch();
    		}
    		return u[pos];
    	}
    	cout<<"Incorrect password\n";
    	return fail();
    }
    2.Changing password

    Code:
    user user::change_password()
    {
    	user u;
    	u=login();
    	.
    	.          //The problem occurs within this.Hence,
    	.          //I don't think the rest of the code
    	.          //is required
    	.
    You don't have to read the whole of the first code, because the problem occurs within the first few lines.As you might have guessed, user is the name of a class.

    Now, here is the most weird problem I have ever faced-

    1.If I directly call the directly,login( ) function it executes properly.OK very good.

    2.If I call the login() function from change_password () function(by running it normally using ctrl+F9) it shows divide error exception.OK maybe something to do with the arguments passed.

    3.If I execute the same function, through the same change_password () function, step by step,it shows General Protection Fault(not divide error exception)!!!

    That's not all!!When I execute the change_password () function normally ,it fails to clear the screen itself ( the very first statement).Howe ver if I execute the same function step by step it get struck just before array of object is initialised( 3rd statement). Like I already mentioned if I directly call the login() function it does not show any error.Hence it has gone nothing to do with the array size.

    Someone please explain this weird behaviour to me and correct my code.I appreciate an early response.
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    The first thing I see is that login() is supposed to return a user but there are places where it's returning fail(). That fail appears to trigger a user constructor so login() returns a corrupt object.

    As a rule in C++ functions should receive reference arguments so there's nothing to return. The function return value would then be available for pass/fail values.

    Comment

    • K Siddharth
      New Member
      • Dec 2015
      • 8

      #3
      @weaknessforcat s

      Forget about returning values.It encounters the exception even before the declaration of object takes place.Moreover if what you told is right, then when I directly call login() function, it shouldn't work.But in reality it does work properly.

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        What does user::operator= look like? You might post the user class code.

        What exception?

        Also, when you say it works when you call login() directly do you mean:

        Code:
        int main()
        {
           login();
        }
        or do you mean:

        Code:
        int main()
        {
        user u;
        u=login();
        }
        I do say again that the return from fail() is not a valid user constructor argument. You need to have a user& as an argument to user::change_pa ssword. That way you can use the return from login() for fail() as you are currently doing.

        Note also that the return from user::change_pa ssword is a user object and the only one around is a local object which I presume is returned so that would trigger a copy constructor call to get from the local user object to the returned user object. I would like to see the user copy constructor.

        Where is the password? Is the object used by user::change_pa ssword the this object? If so, then why have a user object in this code when the this is all you need.

        Hopefully your code post will clear this up

        Comment

        • K Siddharth
          New Member
          • Dec 2015
          • 8

          #5
          I haven't defined an operator like '=' in my class.Instead,I have used the operator '=' which the compiler itself provides. I have done so,because there are too many members in the class and none of these require a change in value when an object is initialized to another object.Hence,I would be wasting ultra lot of time for typing this, but would gain nothing.But anyway, since you asked for the class definition of 'user', here it is-

          Code:
          class user
          {
          	char name[30],pass[30];
          	unsigned int pts,n_pts;
          	short int dif,a_dif,prev_mis,no_wins,cons_mis,cons_switch,tot_wins,loss;
          	float wrong;
          	public:user(char n[]="\0\0\0",char p[]="\0\0\0")
          	{
          		strcpy(name,n);
          		strcpy(pass,p);
          		pts=n_pts=dif=a_dif=prev_mis=no_wins=cons_mis=cons_switch=cons_switch=tot_wins=loss=0;
          		wrong=0;
          	}
          
          	/*The code after this
          	has all member functions
          	[I]declared[/I] within it*/
          	.
          	.
          	.
          	
          };
          When I said "calling the login() function directly" ,I meant the second code, which you gave.

          The function fail() is not a constructor.It is a user-defined(non-member) function, which is defined this way-

          Code:
          inline user fail()
          {
          	user u;
          	return u;              
          }
          Here, the function fail() makes use of the fact that the default constructor is called when an object of a class is initialized normally(withou t parameters).So basically, this function initializes an object u with username like "\0\0\0"(se e the constructor of the user function) and returns this.Hence any object, which is returned from the function with username like "\0\0\0" is taken as failure.This proves the significance of using "return fail()" statement frequently.Also , there is no way of typing 4 null characters on the key board.Hence,thi s is the only way how this fail() value can be returned.Hence, no clashes can take place.I haven't directly returned the user() constructor directly b'coz it affects the program's understandabili ty.

          ok.Maybe the working of the fail() function would be a little confusing.But my point here is that the function fail () is not a constructor of some other class, nor does it return an object of some other class.Hence, there is no chance this can give corrupted values.

          This program does not have a copy constructor defined in it. Instead, uses the copy constructor provided by the compiler, again b'coz of those 2 reasons, which I had already mentioned above(the reasons for not defining the operator '=').

          Password as you would have recognized above, is a member of the class user.

          The function user::change_pa ssword() doesn't use the this object.

          Hopefully I have clarified all your doubts.
          Last edited by K Siddharth; Dec 31 '15, 03:38 PM. Reason: Enhancing the clarity

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            I am trying to get a test program working but I find that inside user::change_pa ssword there is a login() but the function that was posted as user::login(sho rt int pur) won't compile as a
            login(). One has arguments and the other doesn't. Are there two login one of which is not a member function?

            Comment

            • K Siddharth
              New Member
              • Dec 2015
              • 8

              #7
              yeah.One is a non member function and the other the member function. Both functions have 1 parameter with default argument.The non member function just declares an object of user datatype, to invoke the member function.Here is the non member function, just in case u want-
              Code:
              inline user login(int pur=0)
              {
              	user u;
              	u=u.login(pur);
              	return u;
              }

              Comment

              • K Siddharth
                New Member
                • Dec 2015
                • 8

                #8
                and the second statement in the change_password () function was
                Code:
                u=login([I]1[/I])
                not
                Code:
                u=login()
                .

                I'd changed the statement for debugging purposes and had left it like that itself.Anyways, both show the same error though

                Comment

                • weaknessforcats
                  Recognized Expert Expert
                  • Mar 2007
                  • 9214

                  #9
                  I am able to run your code without a crash using this main():

                  Code:
                  int main()
                  {
                  	user u;
                  	user x("HELLO", "WORLD");
                  
                  	u = x;
                  
                  	u = fail();
                  
                  	u = login(1);
                  }
                  The only changes I made were:

                  1) a phony user.dat file
                  2) commented out //int pos = search(u, n, i); in user::change_pa ssword and set pos =0 instead. I didn't have the search function.

                  That said, there may be a problem in the search. That's the sort of thing where you can get a general protection fault.

                  My test main runs to completion with or without the debugger.

                  You might post the search code so I can add it to my test program.

                  Comment

                  • K Siddharth
                    New Member
                    • Dec 2015
                    • 8

                    #10
                    Here is the code
                    Code:
                    int search(user a[],char b[],short int ub,int pur=0)
                    {
                    	for(int i=0;i<=ub;i++)
                    	{
                    		if(compare(a[i],b)==0)
                    		{
                    			if(pur!=0)
                    			{
                    				a[i].display();
                    				getch();
                    			}
                    			return i;
                    		}
                    	}
                    	if(pur!=0)
                    		cout<<"User not found\n";
                    	return -1;
                    }
                    Also note that in the main function,I didn't pass any parameters to login() function(The default val ie. 0 was hence the val of pur).I passed 1 as a parameter only in change_password () function.

                    Comment

                    • K Siddharth
                      New Member
                      • Dec 2015
                      • 8

                      #11
                      OK, apart from this, as you mentioned the data file "users.dat" is the only requisite which is probably missing in the information which I have provided.Coinci dentally, the error is shown after an fstream object f is declared (the fstream object is declared before the array of object u and the compiler stops just before declaration of this array of objects that is @ the statement fstream f("users.dat,io s::in|ios::out| ios::binary)).

                      Hence I'll provide you with my code of creating phony users.dat file-

                      Code:
                      #include<fstream.h>
                      #include<conio.h>
                      #include<stdio.h>
                      #include<string.h>
                      class user
                      {
                      	public:
                      	char name[30],pass[30];
                      	unsigned int pts,n_pts;
                      	short int dif,a_dif,prev_mis,no_wins,cons_mis,cons_switch,tot_wins,loss;
                      	float wrong;
                      	user(char n[]="\0\0",char p[]="\0\0")
                      	{
                      		strcpy(name,n);
                      		strcpy(pass,p);
                      		pts=n_pts=dif=a_dif=prev_mis=no_wins=cons_mis=cons_switch=cons_switch=tot_wins=loss=wrong=0;
                      	}
                      };
                      user fail()
                      {
                      	user a;
                      	return a;
                      }
                      int compare(user a,user b)
                      {
                      	int ret=strcmpi(a.name,b.name);
                      	return ret;
                      }
                      void main()
                      {
                      	cout<<"Are you sure you want to add sample users?\nOther contents may get destroyed\n(yes/no)\n";
                      	char ch[10];
                      	gets(ch);
                      	if(strcmpi(ch,"yes")==0)
                      	{
                      		user u[6];
                      		fstream f("users.dat",ios::out|ios::binary),f2("ldr brd.dat",ios::out|ios::binary);
                      		strcpy(u[0].name,"admin");
                      		strcpy(u[0].pass,"admin");
                      		f.write((char*)&u[0],sizeof(user));
                      		for(int i=1;i<5;i++)
                      		{
                      			char ch[15]="Sample ",no[2];
                      			no[0]=i+48;
                      			no[1]='\0';
                      			strcat(ch,no);
                      			strcpy(u[i].name,ch);
                      			strcpy(u[i].pass,ch);
                      			u[i].pts=(i-1)*100;
                      			f.write((char*)&u[i],sizeof(user));
                      		}
                      		while(i>0)
                      		{
                      			if(compare(fail(),u[i])!=0)
                      			{
                      				f2.write((char*)&u[i],sizeof(user));
                      			}
                               i--;
                      		}
                      		cout<<"Successfully added\n";
                      		f.close();
                      		f2.close();
                      	}
                      }
                      Hopefully, this helps you debug the error.

                      Comment

                      • donbock
                        Recognized Expert Top Contributor
                        • Mar 2008
                        • 2427

                        #12
                        I'm more C than C++, so these comments may not be correct or pertinent...
                        1. Lines 7-8 of user::login. What if users.dat contains more than 10 entries? Don't see anything in this loop to protect you from running past the end of u.
                        2. Lines 8 and 13 of user::login; line 3 of search. Shouldn't line 3 of search be i<ub rather than i<=ub?

                        Comment

                        • K Siddharth
                          New Member
                          • Dec 2015
                          • 8

                          #13
                          Thx donbock.But it actually doesn't help.

                          Comment

                          • weaknessforcats
                            Recognized Expert Expert
                            • Mar 2007
                            • 9214

                            #14
                            I notice you are using gets() and not fgets(). gets() only works with stdin and copies to a buffer until it reaches a newline. It leaves the newline in stdin for the next operation to trip over and does not let you specify a buffer size leading to overruns followed by general protection faults
                            gets() has been removed from C++ in 2011 and is effectively removed from C.

                            You might consider using fgets().

                            In any case add some error checking code to test the return from gets() to see if any error occurred.

                            Comment

                            Working...