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. [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 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