> --nextPart2143034.hU0dofkB2d > > Actually, once you've got your head around the fact that nobody is > there to hold your hand, it isn't too bad. The attached trial program > has been tested and is always safe. I'm going to commit this to > XForms cvs. >
Unfrotunately Angus' fix is buggy too, because at least on some systems size_t is unsigned (linux being a prime example). If so and fname_size>fname_capacity then the last strncat gets a huge limit (more than INT_MAX) and the buffer overflow will works anyway. Also it could be attacked by integer overflow, albeit not on most systems. Also Angus put the terminator in too early---unless strncat guarantees termination tje '\0' might get clobbered. A suggested alternative, which returns 1 if everything is OK and 0 if fname is too small, if attached. main has been changed to reflect this change, without which people could use overflows to get unexpected filenames. I have replaced most of the str* functions with snprintf, which makes the code *much* simpler. You could simplify it even more if you assumed everyone's snprintf followed C99.
#include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> typedef struct { char * output_dir; } FD_Opt; FD_Opt fdopt; static char const * filename_only(char const * filename) { char const * ptr = strrchr(filename, '/'); if (ptr) return ptr+1; return filename; } static int build_fname(char * fname, size_t fname_capacity, char const * filename, char const * ext) { static const char null='\0'; char const * const only_filename = filename_only(filename); size_t l; const char *dname; const char *slash; int npc; slash=&null; if (fdopt.output_dir) { l = strlen(fdopt.output_dir); if (fdopt.output_dir[l-1]!='/') slash="/"; dname=fdopt.output_dir; } else dname=&null; npc=snprintf(fname, fname_capacity, "%s%s%s", dname, slash, only_filename); /* npc==-1 is glibc <= 2.0.6 and npc >= fname_capacity is C99 */ return (npc==-1 || npc>= fname_capacity) ? 0 : 1; } int main(int argc, char * argv[]) { size_t const fname_capacity = 10; char fname[fname_capacity + 1]; fdopt.output_dir = 0; if (argc > 1) { fdopt.output_dir = (char *)malloc(strlen(argv[1]) + 1); strcpy(fdopt.output_dir, argv[1]); } if (build_fname(fname, fname_capacity, "foo/bar/bazabcde", ".h")) printf("Output fname is \"%s\"\n", fname); else { fprintf(stderr, "%s: output file name too big.\n", argv[0]); exit(EXIT_FAILURE); } return 0; }
Duncan (-: "software industry, the: unique industry where selling substandard goods is legal and you can charge extra for fixing the problems."