Note: This is a beta release of Red Hat Bugzilla 5.0. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Also email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback here.

Bug 86439

Summary: memccpy() can read past end of source string
Product: Red Hat Enterprise Linux 2.1 Reporter: Jason Uhlenkott <jasonuhl>
Component: glibcAssignee: Jakub Jelinek <jakub>
Status: CLOSED ERRATA QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 2.1CC: fweimer
Target Milestone: ---   
Target Release: ---   
Hardware: ia64   
OS: Linux   
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2003-05-22 16:42:16 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Jason Uhlenkott 2003-03-21 23:35:25 UTC
The memccpy() call below will cause a segmentation fault on ia64
systems:  It tries to read beyond the end of srcbuf and hits an
unreadable page.  Is this a bug?

Note that we're deliberately indicating a size of SIZE+8 characters to
memccpy even though srcbuf is only SIZE characters long.

One point of view is that memccpy should never attempt to read more
than SIZE characters:  It should see the 0 character at srcbuf[SIZE-1]
and stop there.  memccpy() is supposed to stop after it copies n
characters or after it copies the character specified by the argument
c, whichever comes first, so obviously it's ok for the source string
to be shorter than n characters.

Another point of view is that just because it only copies SIZE
characters, that doesn't mean it will only try to access SIZE
characters from the source string.  The length of the source string is
allowed to be less than n characters, but the size of the object
containing the source string isn't.

The C standard contains some explicit language which comes down on the
side of the latter point of view.  Section 7.21.1 paragraph 2 (I'm
quoting from C99 since that's what I have handy, but C89/C90 has the
same requirements):
| Where an argument declared as size_t n specifies the length of the
| array for a function, n can have the value zero on a call to that
| function.  Unless explicitly stated otherwise in the description of a
| particular function in this subclause, pointer arguments on such a
| call shall still have valid values, as described in 7.1.4.
Section 7.1.4 states:
| If a function argument is described as being an array, the pointer
| actually passed to the function shall have a value such that all
| address computations and accesses to objects (that would be valid if
| the pointer did point to the first element of such an array) are in
| fact valid.
So if memccpy were a standard C function, we'd clearly be invoking
undefined behavior by doing what we're doing.  memccpy is not part of
the standard C library however.

One point which has caused some consternation is that these two
statements are expected to behave identically:
        memccpy(dstbuf, srcbuf, 0, SIZE+8);
        strncpy(dstbuf, srcbuf, SIZE+8);
Yet the memccpy call causes a segfault while the strncpy call does

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <assert.h>

#define SIZE 32768

int main(void) {

        int fd;
        char *srcbuf;
        char dstbuf[2*SIZE];
        char *protected;

        fd = open("/dev/zero", O_RDONLY);
        if(fd == -1) {

        srcbuf = mmap(0, SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
        if(srcbuf == (char *)-1) {
        protected = mmap(srcbuf+SIZE, SIZE, PROT_NONE,
                MAP_FIXED|MAP_PRIVATE, fd, SIZE);
        if(protected == (char *)-1) {
        assert(protected == srcbuf+SIZE);

        memset(srcbuf, 'x', SIZE-1);

#if 1
        memccpy(dstbuf, srcbuf, 0, SIZE+8);
        strncpy(dstbuf, srcbuf, SIZE+8);

        return 0;

Comment 1 Mark J. Cox 2003-05-22 16:42:17 UTC
An errata has been issued which should help the problem described in this bug report. 
This report is therefore being closed with a resolution of ERRATA. For more information
on the solution and/or where to find the updated files, please follow the link below. You may reopen 
this bug report if the solution does not work for you.