sscanf problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • utab

    sscanf problem

    Dear all,

    I have to interface some C code in C++, but I had a problem with sscanf
    function, it has been some time I have not used C and I could not figure
    out my problem. Simple code is below, I am trying to read a file with
    line line 8 characters wide,

    88888888

    it has unix line ending LF, but I am getting a segfault from the sscanf
    line. Maybe I am misusing some of the standard C functions, can you help
    me locate this?

    Best,

    #include <stdio.h>
    #include <string.h>
    int main()
    {
    FILE *fp;
    char buffer[9];
    char *Title;
    char *dummy;
    int ret;
    fp = fopen("deneme", "r");
    dummy = fgets(buffer,9, fp);
    puts(dummy);
    printf("line %s\n",buffer);
    printf("len %d\n",(int)strl en(buffer));
    ret = sscanf(buffer, "%8c%[^\n]", Title,dummy);
    printf("read %d\n",ret);
    return 0;
    }
  • Eric Sosman

    #2
    Re: sscanf problem

    utab wrote:
    Dear all,
    >
    I have to interface some C code in C++, but I had a problem with sscanf
    function, it has been some time I have not used C and I could not figure
    out my problem. Simple code is below, I am trying to read a file with
    line line 8 characters wide,
    >
    88888888
    >
    it has unix line ending LF, but I am getting a segfault from the sscanf
    line. Maybe I am misusing some of the standard C functions, can you help
    me locate this?
    >
    Best,
    >
    #include <stdio.h>
    #include <string.h>
    int main()
    {
    FILE *fp;
    char buffer[9];
    char *Title;
    char *dummy;
    int ret;
    fp = fopen("deneme", "r");
    dummy = fgets(buffer,9, fp);
    puts(dummy);
    printf("line %s\n",buffer);
    printf("len %d\n",(int)strl en(buffer));
    ret = sscanf(buffer, "%8c%[^\n]", Title,dummy);
    What does Title point to? Hint: What value did you assign
    to it?

    There are other problems here, too. The characters matched
    by "%[^\n]" will be stored where dummy points, and where is that?
    It's pointing to the start of buffer, the place the characters
    are being taken from. That's a recipe for the kind of confusion
    that the C Standard calls "undefined behavior."

    Also, once you arrange for Title to point at something of
    use, be aware that "%8c" will store only the eight characters it
    consumes, without a trailing '\0'. There's nothing inherently
    wrong with that, but it means that the stored characters will not
    be a well-formed string; apply strlen() to them or try to print
    them with "%s" or something, and you'll get U.B. yet again.
    printf("read %d\n",ret);
    return 0;
    }
    One parting remark: Many of the functions you call can fail
    if files don't exist or don't contain what you thought they did.
    If they fail, they report their failure by returning special
    values (which depend on the function and sometimes on the kind
    of failure). You should check the returned values before just
    plowing ahead; failure to do so is equivalent to driving a car
    with your eyes closed.

    --
    Eric.Sosman@sun .com

    Comment

    • jameskuyper@verizon.net

      #3
      Re: sscanf problem

      utab wrote:
      Dear all,
      >
      I have to interface some C code in C++, but I had a problem with sscanf
      function, it has been some time I have not used C and I could not figure
      out my problem. Simple code is below, I am trying to read a file with
      line line 8 characters wide,
      >
      88888888
      >
      it has unix line ending LF, but I am getting a segfault from the sscanf
      line. Maybe I am misusing some of the standard C functions, can you help
      me locate this?
      >
      Best,
      >
      #include <stdio.h>
      #include <string.h>
      int main()
      It would be better to say int main(void)
      {
      FILE *fp;
      char buffer[9];
      char *Title;
      char *dummy;
      int ret;
      fp = fopen("deneme", "r");
      You should verify that fopen() succeeded before you attempt to do
      anything else with 'fp'. If it failed, every statement after this one
      that uses fp has undefined behavior.
      dummy = fgets(buffer,9, fp);
      You don't bother to check whether or not the fgets() call succeeded.
      If it fails, dummy will be a null pointer, and all further uses of
      dummy in this program will have undefined behavior.
      puts(dummy);
      printf("line %s\n",buffer);
      printf("len %d\n",(int)strl en(buffer));
      If the input line is actually 9 characters or longer, buffer[8] will
      be set to the value of the 9th character, not a '\n'. If it is 8
      characters long, buffer[8] will contain '\n'; in neither case will the
      buffer be null-terminated. As a result, all three of those statements
      will attempt to read past the end of buffer to find a terminating
      '\0', reading memory locations that you might not have permission to
      read. The behavior is undefined.

      You should consider the possibility of incorrectly formated input
      lines, which means that you should first check to see whether and
      where a '\n' character appears in that line - use memchr(), not
      strchr(), since if the line is more than 7 characters long, the buffer
      won't contain a null terminated string, and if its more than 8
      characters long, strchr() won't stop searching until after it attempts
      to read memory outside of buffer. It's up to you whether you're
      willing to assume that your inputs will always be correctly formatted;
      I don't recommend making that assumption

      Either way, you should, at the very least, set buffer to '\0', before
      performing any string operations on buffer.
      ret = sscanf(buffer, "%8c%[^\n]", Title,dummy);
      You're telling sscanf to read the first 8 characters of buffer into
      the location pointed at by Title. Problem: at this point, Title is
      uninitialized, so if it contains a valid pointer, that's purely by
      accident. If that pointer is vaild, there's no guarantee that it
      points at a memory location that you have permission to write to. This
      is the probably the cause of your segfault. If Title were initialized
      at this point, memcpy() would be a better way to do the same thing.

      If sscanf() somehow manages to survive that step without segfaulting,
      it will then start reading from the buffer starting at buffer[8], and
      it will continue reading until it finds a '\n' character. Assuming
      that the file was opened and read successfully, and that the input
      line is 8 characters long, it will find it at the very next character.
      Having found nothing to copy, it will then write a terminating null
      character to the location pointed at by dummy.

      Assuming that dummy is not a null pointer at this point, it will point
      at the first char in buffer. Writing to that location is yet another
      thing that makes the behavior of your code undefined.

      Comment

      • Eric Sosman

        #4
        Re: sscanf problem

        jameskuyper@ver izon.net wrote:
        utab wrote:
        >[...]
        > dummy = fgets(buffer,9, fp);
        [...]
        If the input line is actually 9 characters or longer, buffer[8] will
        be set to the value of the 9th character, not a '\n'. If it is 8
        characters long, buffer[8] will contain '\n'; in neither case will the
        buffer be null-terminated. As a result, all three of those statements
        will attempt to read past the end of buffer to find a terminating
        '\0', reading memory locations that you might not have permission to
        read. The behavior is undefined.
        Um, er, no. If the line is too long, fgets() stores as much as
        it can (8 characters, in this case), then tacks on a '\0'. (Unless
        there's an I/O error, in which case nothing useful can be said about
        anything in the buffer.) See 7.19.7.2p2.

        --
        Eric.Sosman@sun .com

        Comment

        • jameskuyper@verizon.net

          #5
          Re: sscanf problem

          Eric Sosman wrote:
          jameskuyper@ver izon.net wrote:
          utab wrote:
          [...]
          dummy = fgets(buffer,9, fp);
          [...]
          If the input line is actually 9 characters or longer, buffer[8] will
          be set to the value of the 9th character, not a '\n'. If it is 8
          characters long, buffer[8] will contain '\n'; in neither case will the
          buffer be null-terminated. As a result, all three of those statements
          will attempt to read past the end of buffer to find a terminating
          '\0', reading memory locations that you might not have permission to
          read. The behavior is undefined.
          >
          Um, er, no. If the line is too long, fgets() stores as much as
          it can (8 characters, in this case), then tacks on a '\0'. (Unless
          there's an I/O error, in which case nothing useful can be said about
          anything in the buffer.) See 7.19.7.2p2.
          You're right - I double-checked the part about "a new-line character
          (which is retained)", but forgot about the part which says "reads at
          most one less than the number of characters specified by n". I use
          fgets() much less frequently than fread(), and I use fread() less
          frequently than I/O routines from the HDF library, so I'm not as
          familiar with the details of fgets() as I should be. Mea culpa.

          Comment

          Working...