Package: aptitude
Version: 0.2.15.9-2

aptitude sometimes goes into an endless loop.

problem is the implementation of prompt_sting in src/cmdline/cmdline_prompt.cc
line 263 ...
    static string prompt_string()
    {
      string rval;
      char buf[1024];
      cin.getline(buf, 1023);
      rval+=buf;

      while(!cin)
        {
          cin.getline(buf, 1023);
          rval+=buf;
        }

      return rval;
    }

to excercise the problem, here is a stripped down and slightly modified version
of that function, including example output:

    ===========================================================
    #include <string>
    #include <iostream>

    using namespace std;

    static string prompt_string_buggy()
    {
      string rval;
      char buf[2];
      cin.getline(buf, 2);
      rval+=buf;
      cerr << " :" << rval << endl;

      while(!cin)
        {
          static int i = 0;
          if (i++ > 10) {
                  cerr << "looping... exiting!" << endl;
                  exit(1);
          }
          cin.getline(buf, 2);
          rval+=buf;
          cerr << " :" << rval << endl;
        }

      return rval;
    }

    int main(int argc, char** argv)
    {
            cout << "input??" << endl;
            cout << prompt_string_buggy();
            return 0;
    }
    ===========================================================

    compile that into "prove-bug".
    then, do

Bug Example 1: ./prove-bug < /dev/null
    input??
     :
     :
     :
     :
     :
     :
     :
     :
     :
     :
     :
     :
    looping... exiting!

Bug Example 2: echo 1234 | ./prove-bug
    input??
     :1
     :1
     :1
     :1
     :1
     :1
     :1
     :1
     :1
     :1
     :1
     :1
    looping... exiting!


    whether the library implementation of getline is correct in not adjusting 
the
    offset (bug example 2), I don't know. this might be a different bug.

    clearly the current implementation does not what is intended in the corner
    cases of end-of-file or very-long-input.

    a simple fix is to simply use the global getline(istream cin,string rval);
    instead of that looping construct...

    similar at the other places where prompt_string() or cin.getline() is used.

my suggested patch is this:

==================================================================
diff -ru aptitude-0.2.15.9/src/cmdline/cmdline_prompt.cc 
aptitude-0.2.15.9_fixed/src/cmdline/cmdline_prompt.cc
--- aptitude-0.2.15.9/src/cmdline/cmdline_prompt.cc     2006-02-11 
11:25:00.000000000 +0100
+++ aptitude-0.2.15.9_fixed/src/cmdline/cmdline_prompt.cc       2006-02-11 
12:46:07.000000000 +0100
@@ -258,24 +258,6 @@
   N_("The following packages will be upgraded:"),
 };
 
-// Probably something like cin.getline() would work, but I don't trust that
-// for interactive use.
-static string prompt_string()
-{
-  string rval;
-  char buf[1024];
-  cin.getline(buf, 1023);
-  rval+=buf;
-
-  while(!cin)
-    {
-      cin.getline(buf, 1023);
-      rval+=buf;
-    }
-
-  return rval;
-}
-
 /** Checks for broken/deleted essential packages and displays a big
  *  fat warning message about them.  Returns false if the user doesn't
  *  want to continue.
@@ -326,15 +308,12 @@
       printf(_("WARNING: Performing this action will probably cause your 
system to break!\n         Do NOT continue unless you know EXACTLY what you are 
doing!\n"));
 
       string prompt=_("I am aware that this is a very bad idea");
-      char buf[1024];
+      string buf;
 
       printf(_("To continue, type the phrase \"%s\":\n"), prompt.c_str());
-      cin.getline(buf, 1023);
+      getline(cin,buf);
       bool rval=(prompt==buf);
 
-      while(!cin)
-       cin.getline(buf, 1023);
-
       return rval;
     }
 
@@ -383,12 +362,15 @@
        {
          printf(_("Do you want to ignore this warning and proceed anyway?\n"));
          printf(_("To continue, enter \"%s\"; to abort, enter \"%s\": "), 
okstr.c_str(), abortstr.c_str());
-         char buf[1024];
-         cin.getline(buf, 1023);
-         buf[1023]='\0';
+         string buf;
+         getline(cin,buf);
+
+         // io-error or end-of-file: do not continue.
+         if(cin.fail() || cin.eof())
+           return false;
 
-         const bool is_ok=(strncasecmp(okstr.c_str(), buf, okstr.size())==0);
-         const bool is_abort=(strncasecmp(abortstr.c_str(), buf, 
abortstr.size())==0);
+         const bool is_ok=(strncasecmp(okstr.c_str(), buf.c_str(), 
okstr.size())==0);
+         const bool is_abort=(strncasecmp(abortstr.c_str(), buf.c_str(), 
abortstr.size())==0);
 
          const bool rval=is_ok;
 
@@ -663,7 +645,8 @@
     printf(_("No packages to show -- enter the package names on the line after 
'i'.\n"));
 
   printf(_("Press Return to continue."));
-  prompt_string();
+  string sink;
+  getline(cin,sink);
 }
 
 // Erm.  Merge w/ above?
@@ -694,7 +677,8 @@
     do_cmdline_changelog(packages);
 
   printf(_("Press Return to continue."));
-  prompt_string();
+  string sink;
+  getline(cin,sink);
 }
 
 bool cmdline_do_prompt(bool as_upgrade,
@@ -732,9 +716,14 @@
              printf(_("Do you want to continue? [Y/n/?] "));
              fflush(stdout);
 
-             string response=prompt_string();
-             string::size_type loc=0;
+             string response;
+             getline(cin,response);
+
+             // io-error or end-of-file: do not continue.
+             if(cin.fail() || cin.eof())
+               return false;
 
+             string::size_type loc=0;
              while(loc<response.size() && isspace(response[loc]))
                ++loc;
 
==================================================================


Thanks,

-- 
: Lars Ellenberg                                  Tel +43-1-8178292-55 :
: LINBIT Information Technologies GmbH            Fax +43-1-8178292-82 :
: Schoenbrunner Str. 244, A-1120 Vienna/Europe   http://www.linbit.com :


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to