[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

libc6 bug? or C programming error?



Here's a bug I believe there is in glibc.  I've filed a bug report, but
I think that bugs.debian.org is sitting on it.  If anyone can point out
what stupidity I have committed that means it isn't really a bug, I'd be
happy!

I should add to the report below that strchr() is used elsewhere in the
program and does not segfault.

                    =============================

Package: libc6
Version: 2.3.2.ds1-10
Severity: normal

I am building a program that at one point uses strchr().  It segfaults in
sysdeps/i386/strchr.S.

I attach a gdb trace.  I am not familiar with assembler so I cannot get
any more information without assistance.

gcc is 3.3.2

I am quite prepared to believe that I have made a mistake in my program, but
I can't see anything wrong at the moment.

root@linda# LD_LIBRARY_PATH=/usr/lib/debug gdb ./pg_default
GNU gdb 6.0-debian
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-linux"...
(gdb) set args -u olly -c cust1
(gdb) directory /usr/src/glibc-2.3.2.ds1/build-tree/glibc-2.3.2/sysdeps/i386:/usr/src/glibc-2.3.2.ds1/build-tree/glibc-2.3.2
Source directories searched: /usr/src/glibc-2.3.2.ds1/build-tree/glibc-2.3.2/sysdeps/i386:/usr/src/glibc-2.3.2.ds1/build-tree/glibc-2.3.2:$cdir:$cwd
(gdb) b pg_files.c:397
Breakpoint 1 at 0x804a8a3: file pg_files.c, line 397.
(gdb) r
Starting program: /usr/src/mypackages/postgresql/alioth/common/pg_default -u olly -c cust1
 
Breakpoint 1, write_cluster_line (user=0x804d9c8 "olly", group=0x804c0c5 "*",
    cluster=0x804dad8 "cust1", db=0x804db60 "", forceflag=0) at pg_files.c:397
397         ptr = strchr(curpos, '\n');
(gdb) p curpos
$1 = 0x4014b000 "# This file maps users against the database clusters to which they will\n# connect by default.  Any user may use \"pg-wrapper -c\" to set a new\n# default to be stored in ~/.postgresqlrc and the existence"...
(gdb) p ptr
$2 = 0x1 <Address 0x1 out of bounds>
(gdb) s
strchr () at ../sysdeps/i386/strchr.S:37
warning: Source file is more recent than executable.
 
37              pushl %edi              /* Save callee-safe registers used here.  */
Current language:  auto; currently asm
(gdb) si
38              movl STR(%esp), %eax
(gdb) si
39              movl CHR(%esp), %edx
(gdb)
46              movb %dl, %dh           /* now it is 0|0|c|c */
(gdb)
47              movl %edx, %ecx
(gdb)
48              shll $16, %edx          /* now it is c|c|0|0 */
(gdb)
49              movw %cx, %dx           /* and finally c|c|c|c */
(gdb)
62              testb $3, %al           /* correctly aligned ? */
(gdb) p $cx
$3 = void
(gdb) p $dx
$4 = void
(gdb) p $3
$5 = void
(gdb) p $al
$6 = void
(gdb) si
63              jz L(11)                /* yes => begin loop */
(gdb) si
124     L(11):  movl (%eax), %ecx       /* get word (= 4 bytes) in question */
(gdb) p $eax
$7 = 1075097600
(gdb) p $ecx
$8 = 2570
(gdb) si
 
Program received signal SIGSEGV, Segmentation fault.
strchr () at ../sysdeps/i386/strchr.S:124
124     L(11):  movl (%eax), %ecx       /* get word (= 4 bytes) in question */
(gdb)


This is the code of the relevant routine; I can give you the whole lot if
you need it:

/********************************************************************
 Write a line in user_clusters 
 ********************************************************************/
void write_cluster_line(const char *user, const char *group,
                        const char *cluster, const char *db,
                        const int forceflag) {
  FILE *ucf;
  char *filename = "/etc/postgresql/user_clusters";
  char *buf, *curpos;
  char *ptr;
  char in[BUFSIZ];
  char c_user[BUFSIZ], c_group[BUFSIZ], junk[BUFSIZ];
  char line[BUFSIZ];
  int c, found = 0, set_default = 0;

  /* create the line to write */
  snprintf(line, BUFSIZ, "%s \t%s \t%s \t%s \t%s\n",
           user, group, cluster,
          (forceflag ? "yes" : "no"),
          (db[0] == '\0' ? "*" : db));
  line[BUFSIZ - 1] = '\0';
  
  /* start of user_clusters - open read-write */
  sprintf(buf, "Failed to open %s for writing", filename);
  if (!(ucf = fopen(filename, "r+"))) {
    /* try creating it */
    if (!(ucf = fopen(filename, "w"))) {
      perror(buf);
      exit(LOC_ERR_WRITE_FAIL);
    }
    /* set permissions and ownership */
    if (fchmod(fileno(ucf), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
      perror ("Could not set perms on user_clusters");
      exit(LOC_ERR_WRITE_FAIL);
    }
    fputs(line, ucf);
    if (!geteuid()) {
      /* we are root - set ownership to postgres.postgres */
      struct passwd *pwd;
      pwd = getpwnam("postgres");
      fchown(fileno(ucf), pwd->pw_uid, pwd->pw_gid);
    }
    fclose(ucf);
    return;
  }
  /* Read it into memory */
  buf = 0;
  if ((c = fseek(ucf, 0, SEEK_END)) == -1) {
    perror("Error seeking in user_clusters");
    exit(LOC_ERR_READ_FAIL);
  }
  if ((c = ftell(ucf)) == -1) {
    perror("Error doing ftell() in user_clusters");
    exit(LOC_ERR_READ_FAIL);
  }
  /* map the file and load an extra page in case the new line expands the
     file across the page boundary; adding 2 allows for the truncating
     effect of integer division.  Forcing an extra page ensures
     that we can identify the end of the buffer by finding a NUL */
  if ((int)(buf = (char *) mmap(buf, ((c / getpagesize()) + 2) * getpagesize(),
                  PROT_NONE, MAP_SHARED, fileno(ucf), 0)) == -1) {
    perror("Could not map user_clusters");
    exit(LOC_ERR_READ_FAIL);
  }
  
  /* Search for the same line and record the start point for writing the
     new one */
  /* Read all users first until we get a match.  If
     there is none, stop at the first group or the default or EOF */
  for (curpos = buf; curpos != '\0' && !found; curpos += c) {

***************   segfaults here in strchr(), first time *********************
    ptr = strchr(curpos, '\n');
    c = (!ptr) ? strlen(curpos) : (ptr - curpos); /* does last line too */
    strncpy(in, curpos, c);
    in[c] = '\0';
    sscanf(in, "%s %s %s", c_user, c_group, junk);
    if (!(strncmp(user, c_user, BUFSIZ))) {
      found = 1;
    }
  }

  if (!(strncmp(user, "*", BUFSIZ))) {
    /* look for the matching group or stop at the default entry or EOF */
    set_default = (strncmp(group, "*", 2) == 0);
    for (; curpos != '\0' && !found; curpos += c) {
      ptr = (strchr(curpos,'\n'));
      c = (!ptr) ? strlen(curpos) : (ptr - curpos); /* does last line too */
      strncpy(in, curpos, c);
      in[c] = '\0';
      sscanf(in, "%s %s %s", c_user, c_group, junk);
      if (!(strncmp(group, c_group, BUFSIZ))) {
        found = 1;
      }
      /* make sure we write a new group before the default line */
      if (!set_default && !strncmp(c_group, "*", 2)) {
        break;
      }
    }
  }

  if (found) {
    /* get the length to position of the next new line or # */
    ptr = strchr(curpos, '#');
    c = (!ptr) ? c : (curpos - ptr);

    /* get length of new line */
    found = strlen(line);
    
    /* move rest of file to leave the correct space for the new line */
    memmove(curpos + found, curpos + c, strlen(curpos + c + 1));
  }

  /* write new line at start position (up to end position) */
  memcpy(curpos, line, c);

  /* commit the file */
  if (msync(curpos, strlen(curpos), MS_INVALIDATE & MS_SYNC) == -1) {
    perror("Failed to write new user_clusters file");
    exit(LOC_ERR_WRITE_FAIL);
  }
  munmap(buf, strlen(buf));
  fclose(ucf);
}


-- System Information:
Debian Release: testing/unstable
Architecture: i386
Kernel: Linux linda 2.4.23linda #1 SMP Tue Dec 2 10:29:43 GMT 2003 i686
Locale: LANG=C, LC_CTYPE=C

Versions of packages libc6 depends on:
ii  libdb1-compat                 2.1.3-7    The Berkeley database routines [gl

-- no debconf information

-- 
Oliver Elphick                                Oliver.Elphick@lfix.co.uk
Isle of Wight, UK                             http://www.lfix.co.uk/oliver
GPG: 1024D/3E1D0C1C: CA12 09E0 E8D5 8870 5839  932A 614D 4C34 3E1D 0C1C
                 ========================================
     "What shall we then say to these things? If God be for 
      us, who can be against us?"              Romans 8:31 



Reply to: