Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d47f5e6
Fix double va_end in v_mi2log_message
gdevenyi Mar 29, 2026
4c67961
Fix FILE leak in milog_init on re-initialization
gdevenyi Mar 29, 2026
0e13f7b
Fix possible NULL dereference in time_stamp after malloc failure
gdevenyi Mar 29, 2026
13d199e
Fix memory leak in alloc2d on partial allocation failure
gdevenyi Mar 29, 2026
5be6f05
Fix NULL dereferences after allocation failures in m2util.c
gdevenyi Mar 29, 2026
d94c176
Fix uninitialized ndims and NULL dereferences in hdf_convenience.c
gdevenyi Mar 29, 2026
80580b3
Fix NULL dereferences after malloc in grpattr.c
gdevenyi Mar 29, 2026
9c87d31
Fix memory leaks and NULL dereferences in dimension.c
gdevenyi Mar 29, 2026
815f0a3
Fix possible NULL dereference after malloc in miget_space_name
gdevenyi Mar 29, 2026
8489cd6
Fix possible NULL dereference in _miget_file_dimension
gdevenyi Mar 29, 2026
276fe2f
Fix NULL dereferences after MALLOC in voxel_loop.c
gdevenyi Mar 29, 2026
750eab4
Fix possible NULL dereference in miexpand_file
gdevenyi Mar 29, 2026
1fe73fa
Fix NULL dereferences and uninitialized variables in files.c
gdevenyi Mar 29, 2026
e95ad20
Fix possible NULL dereference in input_mnc2.c
gdevenyi Mar 29, 2026
4c3b60a
Fix NULL dereference and memory leak in input_nifti.c
gdevenyi Mar 29, 2026
aecf936
Add default cases to MI_TO_DOUBLE and MI_FROM_DOUBLE switch macros
gdevenyi Mar 29, 2026
fb39f84
Fix return type in input_mnc2.c NULL check
gdevenyi Mar 30, 2026
c656bdb
Fix uninitialized chunk_start in MI_icv_access
gdevenyi Mar 30, 2026
9e94e25
Fix uninitialized block_start and block_index in volume_cache.c
gdevenyi Mar 30, 2026
a3b2802
Fix uninitialized var_end in MI_icv_access
gdevenyi Mar 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion libcommon/minc_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,12 @@ void milog_init(const char *name)
const char *fname_str = miget_cfg_str(MICFG_LOGFILE);
int level = miget_cfg_int(MICFG_LOGLEVEL);

/* Close previously opened log file to avoid leak on re-init */
if (_MI_log.fp != NULL && _MI_log.fp != stderr && _MI_log.fp != stdout) {
fclose(_MI_log.fp);
_MI_log.fp = NULL;
}

if (!strlen(fname_str)) {
_MI_log.fp = stderr;
}
Expand Down Expand Up @@ -381,7 +387,6 @@ int v_mi2log_message(const char *file, int line, mimsgcode_t code, va_list ap)
}
fprintf ( _MI2_log.fp, "%s:%d (from %s): ", file, line, minc_routine_name );
vfprintf ( _MI2_log.fp, fmt, ap );
va_end ( ap );
fprintf ( _MI2_log.fp, "\n" );
fflush ( _MI2_log.fp );
}
Expand Down
2 changes: 2 additions & 0 deletions libcommon/time_stamp.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ char *time_stamp(int argc, char *argv[])
length += 2; /* we will need quotes! */
}
str = malloc(length);
if (str == NULL)
return NULL;

/* Copy the time and separator */
(void) strcpy(str, the_time);
Expand Down
12 changes: 8 additions & 4 deletions libsrc/hdf_convenience.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ hdf_get_diminfo(hid_t dst_id, int *ndims, hsize_t dims[])

spc_id = H5Dget_space(dst_id);
if (spc_id < 0) {
*ndims = 0;
MI_LOG_ERROR(MI_MSG_SNH);
}
else {
Expand Down Expand Up @@ -2273,17 +2274,20 @@ hdf_open(const char *path, int mode)
/* OK, it's compound type. */
struct m2_dim *dim = hdf_dim_add(file, MIvector_dimension,
H5Tget_nmembers(type_id));
dim->is_fake = 1;
dims[ndims++] = H5Tget_nmembers(type_id);
is_compound = 1;
if (dim != NULL) {
dim->is_fake = 1;
dims[ndims++] = H5Tget_nmembers(type_id);
is_compound = 1;
}
}
H5Tclose(type_id);
}
#endif /* NO_EMULATE_VECTOR_DIMENSION */

var = hdf_var_add(file, MIimage, "/minc-2.0/image/0/image",
ndims, dims);
var->is_cmpd = is_compound;
if (var != NULL)
var->is_cmpd = is_compound;

H5Dclose(dset_id);
}
Expand Down
4 changes: 2 additions & 2 deletions libsrc/image_conversion.c
Original file line number Diff line number Diff line change
Expand Up @@ -1343,12 +1343,12 @@ PRIVATE int MI_icv_access(int operation, mi_icv_type *icvp, long start[],
for allocating variable buffer
(NULL if we don't care) */
long chunk_count[MAX_VAR_DIMS]; /* Number of elements to get for chunk */
long chunk_start[MAX_VAR_DIMS]; /* Starting index for getting a chunk */
long chunk_start[MAX_VAR_DIMS] = {0}; /* Starting index for getting a chunk */
long chunk_size; /* Size of chunk in bytes */
void *chunk_values; /* Pointer to next chunk to get */
long var_start[MAX_VAR_DIMS]; /* Coordinates of first var element */
long var_count[MAX_VAR_DIMS]; /* Edge lengths in variable */
long var_end[MAX_VAR_DIMS]; /* Coordinates of last var element */
long var_end[MAX_VAR_DIMS] = {0}; /* Coordinates of last var element */
int firstdim;
int idim, ndims;

Expand Down
8 changes: 8 additions & 0 deletions libsrc/minc_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
dvalue = (double) *((unsigned char *) ptr); break; \
case MI_PRIV_SIGNED : \
dvalue = (double) *((signed char *) ptr); break; \
default: dvalue = 0; break; \
} \
break; \
case NC_SHORT : \
Expand All @@ -127,6 +128,7 @@
dvalue = (double) *((unsigned short *) ptr); break; \
case MI_PRIV_SIGNED : \
dvalue = (double) *((signed short *) ptr); break; \
default: dvalue = 0; break; \
} \
break; \
case NC_INT : \
Expand All @@ -135,6 +137,7 @@
dvalue = (double) *((unsigned int *) ptr); break; \
case MI_PRIV_SIGNED : \
dvalue = (double) *((signed int *) ptr); break; \
default: dvalue = 0; break; \
} \
break; \
case NC_FLOAT : \
Expand All @@ -148,6 +151,7 @@
"Attempt to convert NC_NAT value to double"); \
dvalue = 0; \
break; \
default: dvalue = 0; break; \
}

#define MI_FROM_DOUBLE(dvalue, type, sign, ptr) \
Expand All @@ -165,6 +169,7 @@
dvalue = MIN(SCHAR_MAX, dvalue); \
*((signed char *) ptr) = ROUND(dvalue); \
break; \
default: break; \
} \
break; \
case NC_SHORT : \
Expand All @@ -179,6 +184,7 @@
dvalue = MIN(SHRT_MAX, dvalue); \
*((signed short *) ptr) = ROUND(dvalue); \
break; \
default: break; \
} \
break; \
case NC_INT : \
Expand All @@ -193,6 +199,7 @@
dvalue = MIN(INT_MAX, dvalue); \
*((signed int *) ptr) = ROUND(dvalue); \
break; \
default: break; \
} \
break; \
case NC_FLOAT : \
Expand All @@ -207,6 +214,7 @@
"Attempt to convert to NC_NAT from double"); \
dvalue = 0; \
break; \
default: break; \
}

/**/
Expand Down
1 change: 1 addition & 0 deletions libsrc/netcdf_convenience.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ MNCAPI char *miexpand_file(const char *path, char *tempfile, int header_only,
compfile = NULL;
if ((first_ncerr == NC_SYSERR) && (compress_type == UNKNOWN)) {
compfile = MALLOC(strlen(path) + max_compression_code_length + 2, char);
if (compfile == NULL) MI_RETURN(NULL);
for (iext=0; iext < complist_length; iext++) {
(void) strcat(strcpy(compfile, path),
compression_code_list[iext].extension);
Expand Down
12 changes: 12 additions & 0 deletions libsrc/voxel_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,7 @@ PRIVATE void update_history(int mincid, char *arg_string)

/* Allocate a string and get the old history */
string = MALLOC(att_length, char);
if (string == NULL) return;
string[0] = '\0';
(void) miattgetstr(mincid, NC_GLOBAL, MIhistory, att_length,
string);
Expand Down Expand Up @@ -2007,6 +2008,7 @@ PRIVATE Loopfile_Info *initialize_loopfile_info(int num_input_files,

/* Allocate structure */
loopfile_info = MALLOC(1, Loopfile_Info);
if (loopfile_info == NULL) return NULL;

/* Save clobber info */
if (loop_options->clobber) {
Expand All @@ -2029,6 +2031,7 @@ PRIVATE Loopfile_Info *initialize_loopfile_info(int num_input_files,
/* Save input file names (just copy pointers, not strings) */
if (num_input_files > 0) {
loopfile_info->input_files = MALLOC(num_input_files, char *);
if (loopfile_info->input_files == NULL) { FREE(loopfile_info); return NULL; }
for (ifile=0; ifile < num_input_files; ifile++)
loopfile_info->input_files[ifile] = input_files[ifile];
}
Expand All @@ -2038,6 +2041,7 @@ PRIVATE Loopfile_Info *initialize_loopfile_info(int num_input_files,
/* Save output file names (just copy pointers, not strings) */
if (num_output_files > 0) {
loopfile_info->output_files = MALLOC(num_output_files, char *);
if (loopfile_info->output_files == NULL) { FREE(loopfile_info); return NULL; }
for (ifile=0; ifile < num_output_files; ifile++)
Comment on lines 2042 to 2045
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If output_files allocation fails, the code frees only loopfile_info but leaks loopfile_info->input_files allocated earlier (and leaves other members potentially uninitialized). Consider initializing the struct members to NULL/MI_ERROR up front and calling cleanup_loopfile_info() (or manually freeing prior allocations) on all early-return error paths.

Copilot uses AI. Check for mistakes.
loopfile_info->output_files[ifile] = output_files[ifile];
}
Expand All @@ -2061,6 +2065,9 @@ PRIVATE Loopfile_Info *initialize_loopfile_info(int num_input_files,
num_free_files -= num_files;
loopfile_info->output_mincid = MALLOC(num_files, int);
loopfile_info->output_icvid = MALLOC(num_files, int);
if (loopfile_info->output_mincid == NULL || loopfile_info->output_icvid == NULL) {
FREE(loopfile_info); return NULL;
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On allocation failure for output_mincid/output_icvid, the code frees only loopfile_info, leaking input_files/output_files (and any other already allocated members). Prefer a single cleanup path (e.g., initialize members then call cleanup_loopfile_info()), or explicitly free previously allocated members before returning.

Suggested change
FREE(loopfile_info); return NULL;
if (loopfile_info->output_mincid != NULL) FREE(loopfile_info->output_mincid);
if (loopfile_info->output_icvid != NULL) FREE(loopfile_info->output_icvid);
if (loopfile_info->output_files != NULL) FREE(loopfile_info->output_files);
if (loopfile_info->input_files != NULL) FREE(loopfile_info->input_files);
FREE(loopfile_info);
return NULL;

Copilot uses AI. Check for mistakes.
}
for (ifile=0; ifile < num_files; ifile++) {
loopfile_info->output_mincid[ifile] = MI_ERROR;
loopfile_info->output_icvid[ifile] = MI_ERROR;
Expand All @@ -2084,6 +2091,9 @@ PRIVATE Loopfile_Info *initialize_loopfile_info(int num_input_files,
num_free_files -= num_files;
loopfile_info->input_mincid = MALLOC(num_files, int);
loopfile_info->input_icvid = MALLOC(num_files, int);
if (loopfile_info->input_mincid == NULL || loopfile_info->input_icvid == NULL) {
FREE(loopfile_info); return NULL;
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On allocation failure for input_mincid/input_icvid, the code frees only loopfile_info, leaking earlier allocations such as input_files, output_files, and output_mincid/output_icvid. Use a cleanup path that frees all partially allocated members before returning.

Suggested change
FREE(loopfile_info); return NULL;
if (loopfile_info->input_mincid != NULL) {
FREE(loopfile_info->input_mincid);
}
if (loopfile_info->input_icvid != NULL) {
FREE(loopfile_info->input_icvid);
}
if (loopfile_info->output_mincid != NULL) {
FREE(loopfile_info->output_mincid);
}
if (loopfile_info->output_icvid != NULL) {
FREE(loopfile_info->output_icvid);
}
if (loopfile_info->input_files != NULL) {
FREE(loopfile_info->input_files);
}
if (loopfile_info->output_files != NULL) {
FREE(loopfile_info->output_files);
}
FREE(loopfile_info);
return NULL;

Copilot uses AI. Check for mistakes.
}
for (ifile=0; ifile < num_files; ifile++) {
loopfile_info->input_mincid[ifile] = MI_ERROR;
loopfile_info->input_icvid[ifile] = MI_ERROR;
Expand Down Expand Up @@ -2732,6 +2742,7 @@ MNCAPI Loop_Options *create_loop_options(void)

/* Allocate structure */
loop_options = MALLOC(1, Loop_Options);
if (loop_options == NULL) return NULL;

/* Fill in the defaults */
loop_options->clobber = FALSE;
Expand Down Expand Up @@ -3227,6 +3238,7 @@ PRIVATE Loop_Info *create_loop_info(void)

/* Allocate structure */
loop_info = MALLOC(1, Loop_Info);
if (loop_info == NULL) return NULL;

/* Fill in the defaults */
initialize_loop_info(loop_info);
Expand Down
4 changes: 4 additions & 0 deletions libsrc2/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ int miget_space_name ( mihandle_t volume, char **name )
*/
length = strlen ( MI_NATIVE );
*name = malloc ( length + 1 );
if ( *name == NULL )
return ( MI_ERROR );
strcpy ( *name, MI_NATIVE );
} else {
*name = malloc ( length + 1 );
if ( *name == NULL )
return ( MI_ERROR );
result = miget_attr_values ( volume, MI_TYPE_STRING, path_list[i],
"spacetype", length+1, *name );
}
Expand Down
18 changes: 18 additions & 0 deletions libsrc2/dimension.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ int micopy_dimension ( midimhandle_t dim_ptr, midimhandle_t *new_dim_ptr )
handle->offsets = ( double * ) malloc ( dim_ptr->length * sizeof ( double ) );

if ( handle->offsets == NULL ) {
free(handle->name);
free(handle);
return ( MI_ERROR );
}
Expand Down Expand Up @@ -133,6 +134,10 @@ int micopy_dimension ( midimhandle_t dim_ptr, midimhandle_t *new_dim_ptr )
handle->widths = ( double * ) malloc ( dim_ptr->length * sizeof ( double ) );

if ( handle->widths == NULL ) {
free(handle->name);
free(handle->offsets);
free(handle->units);
free(handle);
return ( MI_ERROR );
}

Expand Down Expand Up @@ -275,6 +280,8 @@ int micreate_dimension(const char *name, midimclass_t dimclass, midimattr_t attr
break;
case MI_DIMCLASS_ANY:
default:
free(handle->comments);
free(handle->name);
free(handle);
return MI_ERROR;
}
Expand All @@ -285,6 +292,13 @@ int micreate_dimension(const char *name, midimclass_t dimclass, midimattr_t attr
if ( attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED ) {
handle->widths = ( double * ) malloc ( length * sizeof ( double ) );

if ( handle->widths == NULL ) {
free(handle->comments);
free(handle->name);
free(handle);
return ( MI_ERROR );
}

for ( i = 0; i < length; i++ ) {

handle->widths[i] = 1.0;
Expand Down Expand Up @@ -482,6 +496,8 @@ int miset_apparent_dimension_order ( mihandle_t volume, int array_length,
*/
if ( volume->dim_indices == NULL ) {
volume->dim_indices = ( int * ) malloc ( volume->number_of_dims * sizeof ( int ) );
if ( volume->dim_indices == NULL )
return ( MI_ERROR );
memset ( volume->dim_indices, -1, sizeof ( volume->number_of_dims ) );
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memset(volume->dim_indices, -1, sizeof(volume->number_of_dims)) uses the size of the int field, not the number of bytes in the allocated array. This only initializes a few bytes and leaves most entries uninitialized. Use volume->number_of_dims * sizeof(*volume->dim_indices) (or a loop) here.

Suggested change
memset ( volume->dim_indices, -1, sizeof ( volume->number_of_dims ) );
memset ( volume->dim_indices, -1,
volume->number_of_dims * sizeof ( *volume->dim_indices ) );

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -576,6 +592,8 @@ int miset_apparent_dimension_order_by_name ( mihandle_t volume, int array_length
*/
if ( volume->dim_indices == NULL ) {
volume->dim_indices = ( int * ) malloc ( volume->number_of_dims * sizeof ( int ) );
if ( volume->dim_indices == NULL )
return ( MI_ERROR );
memset ( volume->dim_indices, -1, sizeof ( volume->number_of_dims ) );
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same memset sizing bug as above: sizeof(volume->number_of_dims) does not cover the allocated dim_indices array. Initialize volume->dim_indices using volume->number_of_dims * sizeof(*volume->dim_indices) (or a loop).

Suggested change
memset ( volume->dim_indices, -1, sizeof ( volume->number_of_dims ) );
for ( i = 0; i < volume->number_of_dims; i++ ) {
volume->dim_indices[i] = -1;
}

Copilot uses AI. Check for mistakes.
}

Expand Down
8 changes: 8 additions & 0 deletions libsrc2/grpattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ int milist_start ( mihandle_t vol, const char *path, int flags,
}

frame = ( struct milistframe * ) malloc ( sizeof ( struct milistframe ) );
if ( frame == NULL ) {
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If frame allocation fails, grp_id returned by midescend_path() is leaked (no H5Gclose(grp_id)), since data is freed and the function returns. Close grp_id on this error path before returning.

Suggested change
if ( frame == NULL ) {
if ( frame == NULL ) {
H5Gclose ( grp_id );

Copilot uses AI. Check for mistakes.
free ( data );
return ( MI_ERROR );
}
frame->next = NULL;
frame->grp_id = grp_id;
frame->att_idx = 0;
Expand Down Expand Up @@ -905,13 +909,17 @@ int miset_attr_values ( mihandle_t vol, mitype_t data_type, const char *path,
if ( pch != NULL ) {
slength = strlen ( path ) - ( pch - path );
std_name = malloc ( slength + 1 );
if ( std_name == NULL )
return ( MI_ERROR );

for ( i = 0; i < slength; i++ )
std_name[i] = path[pch - path + 1 + i];

std_name[slength] = '\0';
} else {
std_name = malloc ( strlen ( path ) + 1 );
if ( std_name == NULL )
return ( MI_ERROR );
strcpy ( std_name, path );
}

Expand Down
17 changes: 17 additions & 0 deletions libsrc2/m2util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,8 @@ alloc2d ( int n, int m )
mat[i] = ( double * ) malloc ( m * sizeof ( double ) );

if ( mat[i] == NULL ) {
while ( --i >= 0 )
free ( mat[i] );
free(mat);
return NULL;
}
Expand Down Expand Up @@ -2078,6 +2080,8 @@ scaled_maximal_pivoting_gaussian_elimination ( int n,
int success;

s = alloc1d ( n );
if ( s == NULL )
return ( FALSE );

for ( i = 0; i < n; i++ )
row[i] = i;
Expand Down Expand Up @@ -2180,6 +2184,13 @@ scaled_maximal_pivoting_gaussian_elimination_real ( int n,
a = alloc2d ( n, n );
solution = alloc2d ( n, n_values );

if ( row == NULL || a == NULL || solution == NULL ) {
free ( row );
if ( a != NULL ) free2d ( n, a );
if ( solution != NULL ) free2d ( n, solution );
return ( FALSE );
}

for ( i = 0; i < n; i++ ) {
for ( j = 0; j < n; j++ )
a[i][j] = coefs[i][j];
Expand Down Expand Up @@ -2221,6 +2232,12 @@ invert_4x4_matrix ( double matrix[4][4], /**< Input matrix */
mtmp = alloc2d ( 4, 4 );
itmp = alloc2d ( 4, 4 );

if ( mtmp == NULL || itmp == NULL ) {
if ( mtmp != NULL ) free2d ( 4, mtmp );
if ( itmp != NULL ) free2d ( 4, itmp );
return ( MI_ERROR );
}

/* Start off with the identity matrix. */
for ( i = 0; i < 4; i++ ) {
for ( j = 0; j < 4; j++ ) {
Expand Down
2 changes: 2 additions & 0 deletions libsrc2/volume.c
Original file line number Diff line number Diff line change
Expand Up @@ -1219,6 +1219,8 @@ static int _miget_file_dimension(mihandle_t volume, const char *dimname,
snprintf(path, sizeof(path), MI_ROOT_PATH "/dimensions/%s", dimname);
/* Allocate space for the dimension handle */
hdim = (midimhandle_t) malloc(sizeof (*hdim));
if (hdim == NULL)
return (MI_ERROR);
/* Initialize everything to zero */
memset(hdim, 0, sizeof (*hdim));

Expand Down
Loading
Loading