Bug 181415 - sscanf (glibc) read data overrun found with valgrind
Summary: sscanf (glibc) read data overrun found with valgrind
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: glibc
Version: 4.0
Hardware: i686
OS: Linux
medium
medium
Target Milestone: ---
: ---
Assignee: Jakub Jelinek
QA Contact: Brian Brock
URL: ftp://ftp.crc.ca/crc/ravs/sscanf_bug.c
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2006-02-13 21:24 UTC by Phil Blanchfield
Modified: 2007-11-30 22:07 UTC (History)
1 user (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2006-02-13 21:39:07 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)

Description Phil Blanchfield 2006-02-13 21:24:38 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114

Description of problem:
I have discovered a probable problem with sscanf() from glibc-2.3.4-2.13.
Valgrind reports that sscanf() reads past the end of a dynamicly created
structure. I have already submitted this report to the valgrind developers
(in case it was a valgrind bug) and they believe that it is a sscanf bug.

Please see ftp://ftp.crc.ca/crc/ravs/sscanf_bug.c for a complete explanation
and demonstration of this bug.

Here is a code example which generates the error when compiled and run under
valgrind:

// sscanf_bug.c

#define FIELD_SZ 8
#define RES_SZ (512 - FIELD_SZ)

// File header is 512 bytes 
struct FILEHEADER {    
    char    type[FIELD_SZ];   // this will be "     TYP"
    char    reserved[RES_SZ]; // this will be all spaces
};

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
 struct FILEHEADER *header;
 char type[FIELD_SZ+1];
 int i=0;
 char *typedata = "     TYP";

 // create header
 if ((header = (struct FILEHEADER *)malloc(sizeof(struct FILEHEADER))) == NULL)
 {
   fprintf(stderr,"can't allocate header");
   exit(1);
 }

 // initialize the header with data
 strncpy(header->type,typedata,FIELD_SZ); // don't copy the \0
 for(i = 0; i < RES_SZ; i++)
 {
   header->reserved[i]=' ';     // reserved is all spaces (valgrind ERROR)
   //header->reserved[i]='\0';  // reserved is all nulls (** NO valgrind ERROR **)
 }

 ////////////////////////////////////////////////////
 // now sscan the type into a static char array.
 // the %8s should skip the initial 5 spaces and stop after 8 chars are read
 sscanf (header->type,"%8s",type); // valgrind error is here

 //printf("\n%s\n",type); // should print out: \nTYP\n

free(header);
exit(1);

}


Version-Release number of selected component (if applicable):
glibc-2.3.4-2.13

How reproducible:
Always

Steps to Reproduce:
1.Compile the above code with: gcc -O0 -g -o sscanf_bug sscanf_bug.c
2.Run under valgrind with: valgrind --tool=memcheck ./sscanf_bug
3.Note the overrun error reported by valgrind
  

Actual Results:  The following is valgrind output:

==30482== Memcheck, a memory error detector.
==30482== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al.
==30482== Using LibVEX rev 1471, a library for dynamic binary translation.
==30482== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP.
==30482== Using valgrind-3.1.0, a dynamic binary instrumentation framework.
==30482== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al.
==30482== For more details, rerun with: -v
==30482==
==30482== Invalid read of size 1
==30482==    at 0x40068EC: rawmemchr (mac_replace_strmem.c:519)
==30482==    by 0xAB686F: _IO_str_init_static_internal (in /lib/tls/libc-2.3.2.so)
==30482==    by 0xAAA330: vsscanf (in /lib/tls/libc-2.3.2.so)
==30482==    by 0xAA548C: sscanf (in /lib/tls/libc-2.3.2.so)
==30482==    by 0x8048567: main (tst.c:52)
==30482==  Address 0x401C228 is 0 bytes after a block of size 512 alloc'd
==30482==    at 0x4004639: malloc (vg_replace_malloc.c:149)
==30482==    by 0x80484EE: main (tst.c:35)
==30482==
==30482== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 1)
==30482== malloc/free: in use at exit: 0 bytes in 0 blocks.
==30482== malloc/free: 1 allocs, 1 frees, 512 bytes allocated.
==30482== For counts of detected errors, rerun with: -v
==30482== No malloc'd blocks -- no leaks are possible.

Expected Results:  Valgrind should have reported no errors.

Additional info:

I have also tried this under Fedora core 1 (glibc-2.3.2) with the same result.
Valgrind 2.2.0 and 3.1.0 both report the same error.

I have not tried glibc 2.3.6 which is the current release from GNU.

Comment 1 Jakub Jelinek 2006-02-13 21:39:07 UTC
That testcase is invalid.  See ISO C99 7.19.6.7.  The first argument to sscanf
is string, rather than a char array.  Now, 7.1.1 says that a string
is a contiguous sequence of characters terminated by and including the first
null character.  In your testcase you don't pass a string pointer as the
first sscanf argument, but a pointer to character array, not terminated by
null.


Note You need to log in before you can comment on or make changes to this bug.