From e3379f9b4766b1cf8df7f778acd9880391c96d0b Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Thu, 1 Jan 2026 23:21:04 -0500 Subject: [PATCH 1/2] Replaced all strcpy(), strcat(), strncpy() with safer variants The old functions can easily overflow buffers but also they are not allowed under -fbounds-safety at all. Most cases were trivial. strncpy() notably zeros the whole buffer, while strlcpy() does not. I examined each case carefully and in most cases calloc() was used previously meaning the buffer was already zeroed. In one case, added a memset(0) to preserve the behaviour, those I'm not sure it really is necessary. In a few cases, too the opportunity to better move variable declaration to first usage or otherwise refactor a little bit. --- nifti2/nifti2_io.c | 113 ++++++++++++++++++++----------------- nifti2/nifti_tool.c | 3 +- nifticdf/nifticdf.c | 18 +++--- niftilib/nifti1_io.c | 111 +++++++++++++++++++----------------- niftilib/nifti1_test.c | 23 ++++---- niftilib/nifti1_tool.c | 3 +- niftilib/nifti_tester001.c | 8 +-- 7 files changed, 145 insertions(+), 134 deletions(-) diff --git a/nifti2/nifti2_io.c b/nifti2/nifti2_io.c index 862e47a..aed9453 100644 --- a/nifti2/nifti2_io.c +++ b/nifti2/nifti2_io.c @@ -1280,13 +1280,13 @@ char *nifti_strdup(const char *str) { if( !str ) return NULL; /* allow calls passing NULL */ - size_t length = strlen(str); - char *dup = (char *)malloc(length + 1); + size_t length = strlen(str) + 1; + char *dup = (char *)malloc(length); /* check for failure */ - if( dup ) strcpy(dup, str); + if( dup ) strlcpy(dup, str, length); else fprintf(stderr,"** nifti_strdup: failed to alloc %zu bytes\n", - length+1); + length); return dup; } @@ -3524,7 +3524,7 @@ const char * nifti_find_file_extension( const char * name ) ext = name + len - 4; /* make manipulation copy, and possibly convert to lowercase */ - strcpy(extcopy, ext); + strlcpy(extcopy, ext, sizeof(extcopy)); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* if it look like a basic extension, fail or return it */ @@ -3543,11 +3543,13 @@ const char * nifti_find_file_extension( const char * name ) ext = name + len - 7; /* make manipulation copy, and possibly convert to lowercase */ - strcpy(extcopy, ext); + strlcpy(extcopy, ext, sizeof(extcopy)); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* go after .gz extensions using the modifiable strings */ - strcat(elist[0], extgz); strcat(elist[1], extgz); strcat(elist[2], extgz); + strlcat(elist[0], extgz, 8); + strlcat(elist[1], extgz, 8); + strlcat(elist[2], extgz, 8); if( compare_strlist(extcopy, elist, 3) >= 0 ) { if( is_mixedcase(ext) ) { @@ -3730,21 +3732,23 @@ char * nifti_findhdrname(const char* fname) make_uppercase(extzip); } - hdrname = (char *)calloc(sizeof(char),strlen(basename)+8); + size_t hdrnamelength = strlen(basename)+8; + hdrname = (char *)calloc(sizeof(char),hdrnamelength); if( !hdrname ){ fprintf(stderr,"** nifti_findhdrname: failed to alloc hdrname\n"); free(basename); return NULL; } - strcpy(hdrname,basename); - strcat(hdrname,elist[efirst]); + strlcpy(hdrname, basename, hdrnamelength); + strlcat(hdrname, elist[efirst], hdrnamelength); #ifdef FSLSTYLE if (nifti_fileexists(hdrname)) { free(basename); - char *gzname = (char *)calloc(sizeof(char),strlen(hdrname)+8); - strcpy(gzname, hdrname); - strcat(gzname,extzip); + size_t gznamelength = strlen(hdrname)+8; + char *gzname = (char *)calloc(sizeof(char), gznamelength); + strlcpy(gzname, hdrname, gznamelength); + strlcat(gzname, extzip, gznamelength); if (nifti_fileexists(gzname)) { fprintf(stderr,"Image Exception : Multiple possible filenames detected for basename (*.nii, *.nii.gz): %s\n", basename); free(gzname); @@ -3757,7 +3761,7 @@ char * nifti_findhdrname(const char* fname) if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif #ifdef HAVE_ZLIB - strcat(hdrname,extzip); + strlcat(hdrname, extzip, hdrnamelength); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif @@ -3765,11 +3769,11 @@ char * nifti_findhdrname(const char* fname) efirst = 1 - efirst; - strcpy(hdrname,basename); - strcat(hdrname,elist[efirst]); + strlcpy(hdrname, basename, hdrnamelength); + strlcat(hdrname, elist[efirst], hdrnamelength); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB - strcat(hdrname,extzip); + strlcat(hdrname, extzip, hdrnamelength); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif @@ -3808,8 +3812,9 @@ char * nifti_findimgname(const char* fname , int nifti_type) /* check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; - basename = nifti_makebasename(fname); - imgname = (char *)calloc(sizeof(char),strlen(basename)+8); + basename = nifti_makebasename(fname); + size_t imgnamelength = strlen(basename)+8; + imgname = (char *)calloc(sizeof(char),imgnamelength); if( !imgname ){ fprintf(stderr,"** nifti_findimgname: failed to alloc imgname\n"); free(basename); @@ -3827,8 +3832,8 @@ char * nifti_findimgname(const char* fname , int nifti_type) /* only valid extension for ASCII type is .nia, handle first */ if( nifti_type == NIFTI_FTYPE_ASCII ){ - strcpy(imgname,basename); - strcat(imgname,extnia); + strlcpy(imgname, basename, imgnamelength); + strlcat(imgname, extnia, imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } } else { @@ -3842,21 +3847,21 @@ char * nifti_findimgname(const char* fname , int nifti_type) else if (nifti_type == NIFTI_FTYPE_NIFTI2_1) first = 0; else first = 1; /* should match .img */ - strcpy(imgname,basename); - strcat(imgname,elist[first]); + strlcpy(imgname, basename, imgnamelength); + strlcat(imgname, elist[first], imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ - strcat(imgname,extzip); + strlcat(imgname, extzip, imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif /* failed to find image file with expected extension, try the other */ - strcpy(imgname,basename); - strcat(imgname,elist[1-first]); /* can do this with only 2 choices */ + strlcpy(imgname, basename, imgnamelength); + strlcat(imgname, elist[1-first], imgnamelength); /* can do this with only 2 choices */ if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ - strcat(imgname,extzip); + strlcat(imgname, extzip, imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif } @@ -3896,12 +3901,13 @@ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ - iname = (char *)calloc(sizeof(char),strlen(prefix)+8); + size_t inamelength = strlen(prefix)+8; + iname = (char *)calloc(sizeof(char),inamelength); if( !iname ){ fprintf(stderr,"** NIFTI small malloc failure!\n"); return NULL; } - strcpy(iname, prefix); + strlcpy(iname, prefix, inamelength); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ @@ -3920,13 +3926,13 @@ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, } } /* otherwise, make one up */ - else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); - else if( nifti_type == NIFTI_FTYPE_NIFTI2_1 ) strcat(iname, extnii); - else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); - else strcat(iname, exthdr); + else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strlcat(iname, extnii, inamelength); + else if( nifti_type == NIFTI_FTYPE_NIFTI2_1 ) strlcat(iname, extnii, inamelength); + else if( nifti_type == NIFTI_FTYPE_ASCII ) strlcat(iname, extnia, inamelength); + else strlcat(iname, exthdr, inamelength); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ - if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); + if( comp && (!ext || !strstr(iname,extgz)) ) strlcat(iname, extgz, inamelength); #endif /* check for existence failure */ @@ -3971,12 +3977,13 @@ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ - iname = (char *)calloc(sizeof(char),strlen(prefix)+8); + size_t inamelength = strlen(prefix)+8; + iname = (char *)calloc(sizeof(char),inamelength); if( !iname ){ fprintf(stderr,"** NIFTI: small malloc failure!\n"); return NULL; } - strcpy(iname, prefix); + strlcpy(iname, prefix, inamelength); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ @@ -3995,13 +4002,13 @@ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, } } /* otherwise, make one up */ - else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); - else if( nifti_type == NIFTI_FTYPE_NIFTI2_1 ) strcat(iname, extnii); - else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); - else strcat(iname, extimg); + else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strlcat(iname, extnii, inamelength); + else if( nifti_type == NIFTI_FTYPE_NIFTI2_1 ) strlcat(iname, extnii, inamelength); + else if( nifti_type == NIFTI_FTYPE_ASCII ) strlcat(iname, extnia, inamelength); + else strlcat(iname, extimg, inamelength); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ - if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); + if( comp && (!ext || !strstr(iname,extgz)) ) strlcat(iname, extgz, inamelength); #endif /* check for existence failure */ @@ -7325,7 +7332,7 @@ nifti_1_header * nifti_make_new_n1_header(const int64_t arg_dims[8], nifti_datatype_sizes( nhdr->datatype , &nbyper, &swapsize ); nhdr->bitpix = 8 * nbyper ; - strcpy(nhdr->magic, "n+1"); /* init to single file */ + strlcpy(nhdr->magic, "n+1", sizeof(nhdr->magic)); /* init to single file */ return nhdr; } @@ -7457,8 +7464,8 @@ int nifti_convert_nim2n1hdr(const nifti_image * nim, nifti_1_header * hdr) if( nim->nifti_type > NIFTI_FTYPE_ANALYZE ){ /* then not ANALYZE */ - if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcpy(nhdr.magic,"n+1") ; - else strcpy(nhdr.magic,"ni1") ; + if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strlcpy(nhdr.magic, "n+1", sizeof(nhdr.magic)) ; + else strlcpy(nhdr.magic, "ni1", sizeof(nhdr.magic)) ; nhdr.pixdim[1] = (float)fabs(nhdr.pixdim[1]) ; nhdr.pixdim[2] = (float)fabs(nhdr.pixdim[2]) ; @@ -7842,10 +7849,10 @@ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, int doPigz2(nifti_image *nim, struct nifti_2_header nhdr, const nifti_brick_list * NBL) { FILE *pigzPipe; char command[768]; - strcpy(command, "pigz" ); - strcat(command, " -n -f > \""); - strcat(command, nim->fname); - strcat(command, "\""); + strlcpy(command, "pigz", sizeof(command)); + strlcat(command, " -n -f > \"", sizeof(command)); + strlcat(command, nim->fname, sizeof(command)); + strlcat(command, "\"", sizeof(command)); #ifdef _MSC_VER if (( pigzPipe = _popen(command, "w")) == NULL) return -1; @@ -7874,10 +7881,10 @@ int doPigz2(nifti_image *nim, struct nifti_2_header nhdr, const nifti_brick_list int doPigz(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list * NBL) { FILE *pigzPipe; char command[768]; - strcpy(command, "pigz" ); - strcat(command, " -n -f > \""); - strcat(command, nim->fname); - strcat(command, "\""); + strlcpy(command, "pigz", sizeof(command)); + strlcat(command, " -n -f > \"", sizeof(command)); + strlcat(command, nim->fname, sizeof(command)); + strlcat(command, "\"", sizeof(command)); #ifdef _MSC_VER if (( pigzPipe = _popen(command, "w")) == NULL) return -1; @@ -8713,7 +8720,7 @@ int nifti_short_order(void) /* determine this CPU's byte order */ put rhs string into nim->"nam" string, with field size = "sz" */ #define QSTR(nam,sz) if( strcmp(lhs,#nam) == 0 ) \ - strncpy(nim->nam,rhs,sz), nim->nam[sz-1]='\0' + memset(nim->nam, 0, sz), strlcpy(nim->nam,rhs,sz) /*---------------------------------------------------------------------------*/ /*! Take an XML-ish ASCII string and create a NIFTI image header to match. diff --git a/nifti2/nifti_tool.c b/nifti2/nifti_tool.c index ac249bf..dce29d6 100644 --- a/nifti2/nifti_tool.c +++ b/nifti2/nifti_tool.c @@ -6098,8 +6098,7 @@ int fill_field( field_s * fp, int type, int offset, int num, const char * name ) fp->size = 1; /* init before check */ fp->len = num; - strncpy(fp->name, name, sizeof(fp->name)); - fp->name[sizeof(fp->name) - 1] = 0; + strlcpy(fp->name, name, sizeof(fp->name)); switch( type ){ case DT_UNKNOWN: diff --git a/nifticdf/nifticdf.c b/nifticdf/nifticdf.c index bdab933..4228877 100644 --- a/nifticdf/nifticdf.c +++ b/nifticdf/nifticdf.c @@ -11044,17 +11044,19 @@ char const * const inam[]={ NULL , NULL , int nifti_intent_code( const char *name ) { - char *unam , *upt ; - int ii ; - - if( name == NULL || *name == '\0' ) return -1 ; + if( name == NULL || *name == '\0' ) + return -1 ; - unam = (char *)malloc(strlen(name)+1); - strcpy(unam,name); - for( upt=unam ; *upt != '\0' ; upt++ ) *upt = (char)toupper(*upt) ; + size_t size = strlen(name)+1; + char *unam = (char *)malloc(size); + strlcpy(unam,name,size); + for( char *upt=unam ; *upt != '\0' ; upt++ ) + *upt = (char)toupper(*upt) ; + int ii ; for( ii=NIFTI_FIRST_STATCODE ; ii <= NIFTI_LAST_STATCODE ; ii++ ) - if( strcmp(inam[ii],unam) == 0 ) break ; + if( strcmp(inam[ii],unam) == 0 ) + break ; free(unam) ; return (ii <= NIFTI_LAST_STATCODE) ? ii : -1 ; diff --git a/niftilib/nifti1_io.c b/niftilib/nifti1_io.c index 5089df6..fa1ea98 100644 --- a/niftilib/nifti1_io.c +++ b/niftilib/nifti1_io.c @@ -1174,13 +1174,13 @@ char *nifti_strdup(const char *str) { if( !str ) return NULL; /* allow calls passing NULL */ - size_t length = strlen(str); - char *dup = (char *)malloc(length + 1); + size_t length = strlen(str) + 1; + char *dup = (char *)malloc(length); /* check for failure */ - if( dup ) strcpy(dup, str); + if( dup ) strlcpy(dup, str, length); else fprintf(stderr,"** nifti_strdup: failed to alloc %zu bytes\n", - length+1); + length); return dup; } @@ -2610,7 +2610,7 @@ const char * nifti_find_file_extension( const char * name ) ext = name + len - 4; /* make manipulation copy, and possibly convert to lowercase */ - strcpy(extcopy, ext); + strlcpy(extcopy, ext, sizeof(extcopy)); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* if it look like a basic extension, fail or return it */ @@ -2628,11 +2628,13 @@ const char * nifti_find_file_extension( const char * name ) ext = name + len - 7; /* make manipulation copy, and possibly convert to lowercase */ - strcpy(extcopy, ext); + strlcpy(extcopy, ext, sizeof(extcopy)); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* go after .gz extensions using the modifiable strings */ - strcat(elist[0], extgz); strcat(elist[1], extgz); strcat(elist[2], extgz); + strlcat(elist[0], extgz, 8); + strlcat(elist[1], extgz, 8); + strlcat(elist[2], extgz, 8); if( compare_strlist(extcopy, elist, 3) >= 0 ) { if( is_mixedcase(ext) ) { @@ -2792,21 +2794,23 @@ char * nifti_findhdrname(const char* fname) make_uppercase(extzip); } - hdrname = (char *)calloc(sizeof(char),strlen(basename)+8); + size_t hdrnamelength = strlen(basename)+8; + hdrname = (char *)calloc(sizeof(char),hdrnamelength); if( !hdrname ){ fprintf(stderr,"** nifti_findhdrname: failed to alloc hdrname\n"); free(basename); return NULL; } - strcpy(hdrname,basename); - strcat(hdrname,elist[efirst]); + strlcpy(hdrname, basename, hdrnamelength); + strlcat(hdrname, elist[efirst], hdrnamelength); #ifdef FSLSTYLE if (nifti_fileexists(hdrname)) { free(basename); - char *gzname = (char *)calloc(sizeof(char),strlen(hdrname)+8); - strcpy(gzname, hdrname); - strcat(gzname,extzip); + size_t gznamelength = strlen(hdrname)+8; + char *gzname = (char *)calloc(sizeof(char), gznamelength); + strlcpy(gzname, hdrname, gznamelength); + strlcat(gzname, extzip, gznamelength); if (nifti_fileexists(gzname)) { fprintf(stderr,"Image Exception : Multiple possible filenames detected for basename (*.nii, *.nii.gz): %s\n", basename); free(gzname); @@ -2819,7 +2823,7 @@ char * nifti_findhdrname(const char* fname) if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif #ifdef HAVE_ZLIB - strcat(hdrname,extzip); + strlcat(hdrname, extzip, hdrnamelength); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif @@ -2827,11 +2831,11 @@ char * nifti_findhdrname(const char* fname) efirst = 1 - efirst; - strcpy(hdrname,basename); - strcat(hdrname,elist[efirst]); + strlcpy(hdrname, basename, hdrnamelength); + strlcat(hdrname, elist[efirst], hdrnamelength); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB - strcat(hdrname,extzip); + strlcat(hdrname, extzip, hdrnamelength); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif @@ -2870,8 +2874,9 @@ char * nifti_findimgname(const char* fname , int nifti_type) /* check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; - basename = nifti_makebasename(fname); - imgname = (char *)calloc(sizeof(char),strlen(basename)+8); + basename = nifti_makebasename(fname); + size_t imgnamelength = strlen(basename)+8; + imgname = (char *)calloc(sizeof(char),imgnamelength); if( !imgname ){ fprintf(stderr,"** nifti_findimgname: failed to alloc imgname\n"); free(basename); @@ -2889,8 +2894,8 @@ char * nifti_findimgname(const char* fname , int nifti_type) /* only valid extension for ASCII type is .nia, handle first */ if( nifti_type == NIFTI_FTYPE_ASCII ){ - strcpy(imgname,basename); - strcat(imgname,extnia); + strlcpy(imgname, basename, imgnamelength); + strlcat(imgname, extnia, imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } } else { @@ -2903,21 +2908,21 @@ char * nifti_findimgname(const char* fname , int nifti_type) if (nifti_type == NIFTI_FTYPE_NIFTI1_1) first = 0; /* should match .nii */ else first = 1; /* should match .img */ - strcpy(imgname,basename); - strcat(imgname,elist[first]); + strlcpy(imgname, basename, imgnamelength); + strlcat(imgname, elist[first], imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ - strcat(imgname,extzip); + strlcat(imgname, extzip, imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif /* failed to find image file with expected extension, try the other */ - strcpy(imgname,basename); - strcat(imgname,elist[1-first]); /* can do this with only 2 choices */ + strlcpy(imgname, basename, imgnamelength); + strlcat(imgname, elist[1-first], imgnamelength); /* can do this with only 2 choices */ if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ - strcat(imgname,extzip); + strlcat(imgname, extzip, imgnamelength); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif } @@ -2957,9 +2962,10 @@ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ - iname = (char *)calloc(sizeof(char),strlen(prefix)+8); + size_t inamelength = strlen(prefix)+8; + iname = (char *)calloc(sizeof(char),inamelength); if( !iname ){ fprintf(stderr,"** small malloc failure!\n"); return NULL; } - strcpy(iname, prefix); + strlcpy(iname, prefix, inamelength); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ @@ -2978,12 +2984,12 @@ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, } } /* otherwise, make one up */ - else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); - else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); - else strcat(iname, exthdr); + else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strlcat(iname, extnii, inamelength); + else if( nifti_type == NIFTI_FTYPE_ASCII ) strlcat(iname, extnia, inamelength); + else strlcat(iname, exthdr, inamelength); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ - if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); + if( comp && (!ext || !strstr(iname,extgz)) ) strlcat(iname, extgz, inamelength); #endif /* check for existence failure */ @@ -3027,9 +3033,10 @@ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ - iname = (char *)calloc(sizeof(char),strlen(prefix)+8); + size_t inamelength = strlen(prefix)+8; + iname = (char *)calloc(sizeof(char),inamelength); if( !iname ){ fprintf(stderr,"** small malloc failure!\n"); return NULL; } - strcpy(iname, prefix); + strlcpy(iname, prefix, inamelength); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ @@ -3048,12 +3055,12 @@ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, } } /* otherwise, make one up */ - else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); - else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); - else strcat(iname, extimg); + else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strlcat(iname, extnii, inamelength); + else if( nifti_type == NIFTI_FTYPE_ASCII ) strlcat(iname, extnia, inamelength); + else strlcat(iname, extimg, inamelength); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ - if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); + if( comp && (!ext || !strstr(iname,extgz)) ) strlcat(iname, extgz, inamelength); #endif /* check for existence failure */ @@ -5328,7 +5335,7 @@ nifti_image* nifti_simple_init_nim(void) nifti_datatype_sizes( nhdr.datatype , &nbyper, &swapsize ); nhdr.bitpix = 8 * nbyper ; - strcpy(nhdr.magic, "n+1"); /* init to single file */ + strlcpy(nhdr.magic, "n+1", sizeof(nhdr.magic)); /* init to single file */ nim = nifti_convert_nhdr2nim(nhdr,NULL); nim->fname = NULL; @@ -5409,7 +5416,7 @@ nifti_1_header * nifti_make_new_header(const int arg_dims[8], int arg_dtype) nifti_datatype_sizes( nhdr->datatype , &nbyper, &swapsize ); nhdr->bitpix = 8 * nbyper ; - strcpy(nhdr->magic, "n+1"); /* init to single file */ + strlcpy(nhdr->magic, "n+1", sizeof(nhdr->magic)); /* init to single file */ return nhdr; } @@ -5518,8 +5525,8 @@ struct nifti_1_header nifti_convert_nim2nhdr(const nifti_image * nim) if( nim->nifti_type > NIFTI_FTYPE_ANALYZE ){ /* then not ANALYZE */ - if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcpy(nhdr.magic,"n+1") ; - else strcpy(nhdr.magic,"ni1") ; + if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strlcpy(nhdr.magic, "n+1", sizeof(nhdr.magic)) ; + else strlcpy(nhdr.magic, "ni1", sizeof(nhdr.magic)) ; nhdr.pixdim[1] = (float)fabs(nhdr.pixdim[1]) ; nhdr.pixdim[2] = (float)fabs(nhdr.pixdim[2]) ; nhdr.pixdim[3] = (float)fabs(nhdr.pixdim[3]) ; nhdr.pixdim[4] = (float)fabs(nhdr.pixdim[4]) ; @@ -5759,10 +5766,10 @@ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, int doPigz2(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list * NBL) { FILE *pigzPipe; char command[768]; - strcpy(command, "pigz" ); - strcat(command, " -n -f > \""); - strcat(command, nim->fname); - strcat(command, "\""); + strlcpy(command, "pigz", sizeof(command)); + strlcat(command, " -n -f > \"", sizeof(command)); + strlcat(command, nim->fname, sizeof(command)); + strlcat(command, "\"", sizeof(command)); #ifdef _MSC_VER if (( pigzPipe = _popen(command, "w")) == NULL) return -1; @@ -5791,10 +5798,10 @@ int doPigz2(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list int doPigz(nifti_image *nim, struct nifti_1_header nhdr, const nifti_brick_list * NBL) { FILE *pigzPipe; char command[768]; - strcpy(command, "pigz" ); - strcat(command, " -n -f > \""); - strcat(command, nim->fname); - strcat(command, "\""); + strlcpy(command, "pigz", sizeof(command)); + strlcat(command, " -n -f > \"", sizeof(command)); + strlcat(command, nim->fname, sizeof(command)); + strlcat(command, "\"", sizeof(command)); #ifdef _MSC_VER if (( pigzPipe = _popen(command, "w")) == NULL) return -1; @@ -6597,7 +6604,7 @@ int nifti_short_order(void) /* determine this CPU's byte order */ put rhs string into nim->"nam" string, with field size = "sz" */ #define QSTR(nam,sz) if( strcmp(lhs,#nam) == 0 ) \ - strncpy(nim->nam,rhs,sz), nim->nam[sz-1]='\0' + memset(nim->nam, 0, sz), strlcpy(nim->nam,rhs,sz) /*---------------------------------------------------------------------------*/ /*! Take an XML-ish ASCII string and create a NIFTI image header to match. diff --git a/niftilib/nifti1_test.c b/niftilib/nifti1_test.c index 4680835..00fd9bd 100644 --- a/niftilib/nifti1_test.c +++ b/niftilib/nifti1_test.c @@ -19,7 +19,6 @@ int main( int argc , const char *argv[] ) nifti_image *nim ; int iarg=1 , outmode=1 , argn, usegzip=0; char *tmpstr; - size_t ll; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: nifti1_test [-n2|-n1|-na|-a2] infile [prefix]\n" @@ -79,24 +78,24 @@ int main( int argc , const char *argv[] ) free(nim->fname) ; free(nim->iname) ; - ll = strlen(argv[iarg]) ; + size_t ll = strlen(argv[iarg]) + 8 ; tmpstr = nifti_makebasename(argv[iarg]); - nim->fname = (char *)calloc(1,ll+8) ; strcpy(nim->fname,tmpstr) ; - nim->iname = (char *)calloc(1,ll+8) ; strcpy(nim->iname,tmpstr) ; + nim->fname = (char *)calloc(1,ll) ; strlcpy(nim->fname, tmpstr, ll) ; + nim->iname = (char *)calloc(1,ll) ; strlcpy(nim->iname, tmpstr, ll) ; free(tmpstr); if( nim->nifti_type == 1 ){ - strcat(nim->fname,".nii") ; - strcat(nim->iname,".nii") ; + strlcat(nim->fname, ".nii", ll) ; + strlcat(nim->iname, ".nii", ll) ; } else if ( nim->nifti_type == 3 ){ - strcat(nim->fname,".nia") ; - strcat(nim->iname,".nia") ; + strlcat(nim->fname, ".nia", ll) ; + strlcat(nim->iname, ".nia", ll) ; } else { - strcat(nim->fname,".hdr") ; - strcat(nim->iname,".img") ; + strlcat(nim->fname, ".hdr", ll) ; + strlcat(nim->iname, ".img", ll) ; } if (usegzip) { - strcat(nim->fname,".gz"); - strcat(nim->iname,".gz"); + strlcat(nim->fname, ".gz", ll); + strlcat(nim->iname, ".gz", ll); } if( nifti_image_write_status( nim ) ) { fprintf(stderr, "** failed to write nifti_image\n"); diff --git a/niftilib/nifti1_tool.c b/niftilib/nifti1_tool.c index 15bb165..de327f8 100644 --- a/niftilib/nifti1_tool.c +++ b/niftilib/nifti1_tool.c @@ -3347,8 +3347,7 @@ int fill_field( field_s * fp, int type, int offset, int num, const char * name ) fp->size = 1; /* init before check */ fp->len = num; - strncpy(fp->name, name, sizeof(fp->name)); - fp->name[sizeof(fp->name) - 1] = 0; + strlcpy(fp->name, name, sizeof(fp->name)); switch( type ){ case DT_UNKNOWN: diff --git a/niftilib/nifti_tester001.c b/niftilib/nifti_tester001.c index 3fbc065..81acebb 100644 --- a/niftilib/nifti_tester001.c +++ b/niftilib/nifti_tester001.c @@ -80,11 +80,9 @@ static nifti_image * generate_reference_image( const char * write_image_filename reference_header.magic[1]='+'; reference_header.magic[2]='1'; reference_header.magic[3]='\0'; - /* String is purposfully too long */ - strncpy(reference_header.intent_name,"PHANTOM_DATA to be used for regression testing the nifti reader/writer",sizeof(reference_header.intent_name)); - reference_header.intent_name[sizeof(reference_header.intent_name) - 1] = 0; - strncpy(reference_header.descrip,"This is a very long dialog here to use up more than 80 characters of space to test to see if the code is robust enough to deal appropriately with very long and obnoxious lines.",sizeof(reference_header.descrip)); - reference_header.descrip[sizeof(reference_header.descrip) - 1] = 0; + /* String is purposefully too long */ + strlcpy(reference_header.intent_name,"PHANTOM_DATA to be used for regression testing the nifti reader/writer",sizeof(reference_header.intent_name)); + strlcpy(reference_header.descrip,"This is a very long dialog here to use up more than 80 characters of space to test to see if the code is robust enough to deal appropriately with very long and obnoxious lines.",sizeof(reference_header.descrip)); { int nbyper; From 742182f3f675a32b0820ed02699e9e340ba4a338 Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Fri, 2 Jan 2026 00:01:56 -0500 Subject: [PATCH 2/2] Add strlcpy and strlcat implementations for non-BSD and old glibc strlcpy and strlcat came from OpenBSD and have since been added to other BSDs, macOS (and variants), and glibc (though only since 2.38). Add implementations for other platforms. --- string_helper/string_helper.c | 58 +++++++++++++++++++++++++++++++++++ string_helper/string_helper.h | 14 +++++++++ 2 files changed, 72 insertions(+) create mode 100644 string_helper/string_helper.c create mode 100644 string_helper/string_helper.h diff --git a/string_helper/string_helper.c b/string_helper/string_helper.c new file mode 100644 index 0000000..94d7c42 --- /dev/null +++ b/string_helper/string_helper.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +// Apple provides strlcpy and strlcat, so don't redefine them. +#ifndef __APPLE__ + +// libc 2.38 and above provides strlcpy and strlcat, so don't redefine them. +#if defined (__GLIBC__) && ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 38))) + +// --------------------------------------------------------------------------------------------------------------- +size_t strlcpy(char* restrict ioDestination, const char* restrict inSource, size_t inDestinationSize) +{ + assert(inSource); + + size_t sourceLength = strlen(inSource); + + if (inDestinationSize) + { + size_t length = (sourceLength >= inDestinationSize) ? inDestinationSize - 1 : sourceLength; + memcpy(ioDestination, inSource, length); + ioDestination[length] = '\0'; + } + + return sourceLength; +} + + +// --------------------------------------------------------------------------------------------------------------- +size_t strlcat(char* restrict ioDestination, const char* restrict inSource, size_t inDestinationSize) +{ + assert(ioDestination); + assert(inSource); + + size_t destinationLength = strlen(ioDestination); + size_t sourceLength = strlen(inSource); + size_t totalLength = destinationLength + sourceLength; + + assert(destinationLength < inDestinationSize); + + ioDestination += destinationLength; + inDestinationSize -= destinationLength; + if (sourceLength >= inDestinationSize) + { + sourceLength = inDestinationSize - 1; + } + memcpy(ioDestination, inSource, sourceLength); + ioDestination[sourceLength] = '\0'; + + return totalLength; +} + +#endif +#endif + + diff --git a/string_helper/string_helper.h b/string_helper/string_helper.h new file mode 100644 index 0000000..b5ca068 --- /dev/null +++ b/string_helper/string_helper.h @@ -0,0 +1,14 @@ +// Apple provides strlcpy and strlcat, so don't redefine them. +#ifndef __APPLE__ + +// libc 2.38 and above provides strlcpy and strlcat, so don't redefine them. +#if defined (__GLIBC__) && ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 38))) + +#include + +size_t strlcpy(char* restrict ioDestination, const char* restrict inSource, size_t inDestinationSize); + +size_t strlcat(char* restrict ioDestination, const char* restrict inSource, size_t inDestinationSize); + +#endif +#endif