Refactor error handling code to eliminate internal ID calls (#4453)

All calls to the H5I routines are now made in API routines (sometimes in
FUNC_ENTER/LEAVE_* macros), except for some calls to H5E_clear_stack() within
the library, but I'm planning to remove those over time.

Also, made all the library internal error messages into static const variables,
instead of malloc'ing them, which means that they can just be referenced
and not copied.

Several new and updated auto-generated header files were necessary to enable
this.
This commit is contained in:
Quincey Koziol 2024-05-09 09:41:57 -05:00 committed by GitHub
parent c2099d0e70
commit 2b5769e2a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 1265 additions and 1108 deletions

2
.gitignore vendored
View File

@ -34,6 +34,8 @@ m4/ltversion.m4
m4/lt~obsolete.m4
src/H5Edefin.h
src/H5Einit.h
src/H5Emajdef.h
src/H5Emindef.h
src/H5Epubgen.h
src/H5Eterm.h
src/H5config.h.in

View File

@ -95,6 +95,8 @@ sub setvers {
$_[0] =~ s/^(\#\s*define\s+H5_VERS_MINOR\s+)\d+/$1$vers[1]/m;
$_[0] =~ s/^(\#\s*define\s+H5_VERS_RELEASE\s+)\d+/$1$vers[2]/m;
$_[0] =~ s/^(\#\s*define\s+H5_VERS_SUBRELEASE\s+\")[^\"]*/$1$vers[3]/m;
$_[0] =~ s/^(\#\s*define\s+H5_VERS_STR\s+\")[^\"]*/
sprintf("%s%d.%d.%d%s%s", $1, @vers[0,1,2], $vers[3]?"-":"", $vers[3])/me;
$_[0] =~ s/^(\#\s*define\s+H5_VERS_INFO\s+\")[^\"]*/
sprintf("%sHDF5 library version: %d.%d.%d%s%s", $1, @vers[0,1,2],
$vers[3]?"-":"", $vers[3])/me;

View File

@ -47,7 +47,7 @@ sub print_warning ($) {
my $fh = shift;
print $fh "\n/* Generated automatically by bin/make_err -- do not edit */\n";
print $fh "/* Add new errors to H5err.txt file */\n\n";
print $fh "/* Add new errors to H5err.txt file */\n";
}
##############################################################################
@ -92,7 +92,7 @@ sub parse_line ($) {
# Get the major error's name & description
($name, $desc) = ($line =~ /^\s*MAJOR,\s*(\w*),\s*(.*)\n/);
#print "MAJOR: name=$name, desc=$desc\n";
# Check if the name already exists as a major or minor error message
if(exists($major{$name}) || exists($minor{$name})) {
die "duplicated name: $name";
@ -103,12 +103,12 @@ sub parse_line ($) {
}
# Parse minor error lines
elsif($line =~ /^\s*MINOR,/) {
my $min_section; # Minor errors have a section they below to also
my $min_section; # Minor errors have a section they belong to also
# Get the minor error's section, name & description
($min_section, $name, $desc) = ($line =~ /^\s*MINOR,\s*(\w*),\s*(\w*),\s*(.*)\n/);
#print "MINOR: min_section=$min_section, name=$name, desc=$desc\n";
# Check for valid section
if(!exists($section{$min_section})) {
die "unknown section: $min_section";
@ -121,7 +121,7 @@ sub parse_line ($) {
# Store the minor errors in a hash table, indexed by the name
$minor{$name}=$desc;
# Add the minor error to the list for the section
push @{$section_list{$min_section}}, $name;
}
@ -130,7 +130,7 @@ sub parse_line ($) {
# Get the section's name & description
($name, $desc) = ($line =~ /^\s*SECTION,\s*(\w*),\s*(.*)\n/);
#print "SECTION: name=$name, desc=$desc\n";
# Check if the section has already been defined
if(exists($section{$name})) {
die "duplicated name: $name";
@ -178,10 +178,10 @@ sub create_public ($) {
print HEADER "\n/*********************/\n";
print HEADER "/* Major error codes */\n";
print HEADER "/*********************/\n\n";
foreach $name (keys %major) {
foreach $name (sort keys %major) {
printf HEADER "#define %-20s (H5OPEN %s_g)\n",$name,$name;
}
foreach $name (keys %major) {
foreach $name (sort keys %major) {
printf HEADER "H5_DLLVAR hid_t %-20s /* %s */\n","${name}_g;",$major{$name};
}
@ -189,14 +189,14 @@ sub create_public ($) {
print HEADER "\n/*********************/\n";
print HEADER "/* Minor error codes */\n";
print HEADER "/*********************/\n";
while ( ($sect_name, $sect_desc) = each (%section)) {
print HEADER "\n/* $sect_desc */\n";
foreach $sect_name (sort keys %section) {
print HEADER "\n/* $section{$sect_name} */\n";
# Iterate over all the minor errors in each section
for $name ( @{$section_list{$sect_name}}) {
for $name (sort @{$section_list{$sect_name}}) {
printf HEADER "#define %-20s (H5OPEN %s_g)\n",$name,$name;
}
for $name ( @{$section_list{$sect_name}}) {
for $name (sort @{$section_list{$sect_name}}) {
printf HEADER "H5_DLLVAR hid_t %-20s /* %s */\n","${name}_g;",$minor{$name};
}
}
@ -213,6 +213,84 @@ sub create_public ($) {
close HEADER;
}
##############################################################################
# Create the generated portion of the H5E major message definition code
#
sub create_majdef ($) {
my $prefix = shift; # Get the prefix for the generated file
my $file = "H5Emajdef.h"; # Name of file to generate
my $name; # Name of error message
# Rename previous file
# rename "${prefix}${file}", "${prefix}${file}~" or die "unable to make backup";
# Open new header file
open HEADER, ">${prefix}${file}" or die "unable to modify source";
# Create file contents
print_copyright(*HEADER);
print_warning(*HEADER);
print_startprotect(*HEADER, $file);
# Iterate over all the major errors
print HEADER "\n/***********************************/\n";
print HEADER "/* Major error message definitions */\n";
print HEADER "/***********************************/\n\n";
print HEADER "/* clang-format off */\n";
foreach $name (sort keys %major) {
printf HEADER "static const H5E_msg_t ${name}_msg_s = {false, \"${major{$name}}\", H5E_MAJOR, &H5E_err_cls_s};\n";
}
print HEADER "/* clang-format on */\n";
print_endprotect(*HEADER, $file);
# Close header file
close HEADER;
}
##############################################################################
# Create the generated portion of the H5E minor message definition code
#
sub create_mindef ($) {
my $prefix = shift; # Get the prefix for the generated file
my $file = "H5Emindef.h"; # Name of file to generate
my $name; # Name of error message
my $sect_name; # Section of minor error messages
# Rename previous file
# rename "${prefix}${file}", "${prefix}${file}~" or die "unable to make backup";
# Open new header file
open HEADER, ">${prefix}${file}" or die "unable to modify source";
# Create file contents
print_copyright(*HEADER);
print_warning(*HEADER);
print_startprotect(*HEADER, $file);
# Iterate over all the minor error sections
print HEADER "\n/***********************************/\n";
print HEADER "/* Minor error message definitions */\n";
print HEADER "/***********************************/\n\n";
print HEADER "/* clang-format off */\n";
foreach $sect_name (sort keys %section) {
print HEADER "\n/* $sect_name: $section{$sect_name} */\n";
# Iterate over all the minor errors in each section
for $name (sort @{$section_list{$sect_name}}) {
printf HEADER "static const H5E_msg_t ${name}_msg_s = {false, \"${minor{$name}}\", H5E_MINOR, &H5E_err_cls_s};\n";
}
}
print HEADER "/* clang-format on */\n";
print_endprotect(*HEADER, $file);
# Close header file
close HEADER;
}
##############################################################################
# Create the generated portion of the H5E initialization code
#
@ -220,6 +298,7 @@ sub create_init ($) {
my $prefix = shift; # Get the prefix for the generated file
my $file = "H5Einit.h"; # Name of file to generate
my $name; # Name of error message
my $last_name; # Name of previous error message
my $desc; # Description of error message
my $sect_name; # Section of minor error messages
my $sect_desc; # Description of section
@ -242,18 +321,17 @@ sub create_init ($) {
print HEADER "\n/*********************/\n";
print HEADER "/* Major error codes */\n";
print HEADER "/*********************/\n\n";
foreach $name (keys %major) {
print HEADER " "x(0*$indent),"assert(${name}_g==H5I_INVALID_HID);\n";
print HEADER " "x(0*$indent),"if((msg = H5E__create_msg(cls, H5E_MAJOR, \"${major{$name}}\"))==NULL)\n";
print HEADER " "x(1*$indent),"HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, \"error message initialization failed\");\n";
print HEADER " "x(0*$indent),"if((${name}_g = H5I_register(H5I_ERROR_MSG, msg, false))<0)\n";
foreach $name (sort keys %major) {
print HEADER "/* $name */\n";
print HEADER " "x(0*$indent),"assert(H5I_INVALID_HID == ${name}_g);\n";
print HEADER " "x(0*$indent),"if((${name}_g = H5I_register(H5I_ERROR_MSG, &${name}_msg_s, false)) < 0)\n";
print HEADER " "x(1*$indent),"HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, \"can't register error message\");\n";
if ($first_major == 0) {
print HEADER " "x(0*$indent),"\n/* Remember first major error code ID */\n";
print HEADER " "x(0*$indent),"assert(H5E_first_maj_id_g==H5I_INVALID_HID);\n";
print HEADER " "x(0*$indent),"H5E_first_maj_id_g = ${name}_g;\n\n";
$first_major = 1;
}
}
$last_name = $name;
}
print HEADER " "x(0*$indent),"\n/* Remember last major error code ID */\n";
@ -264,15 +342,14 @@ sub create_init ($) {
print HEADER "\n/*********************/\n";
print HEADER "/* Minor error codes */\n";
print HEADER "/*********************/\n\n";
while ( ($sect_name, $sect_desc) = each (%section)) {
print HEADER "\n"," "x(0*$indent),"/* $sect_desc */\n";
foreach $sect_name (sort keys %section) {
print HEADER "\n/* $section{$sect_name} */\n";
# Iterate over all the minor errors in each section
for $name ( @{$section_list{$sect_name}}) {
print HEADER " "x(0*$indent),"assert(${name}_g==H5I_INVALID_HID);\n";
print HEADER " "x(0*$indent),"if((msg = H5E__create_msg(cls, H5E_MINOR, \"${minor{$name}}\"))==NULL)\n";
print HEADER " "x(1*$indent),"HGOTO_ERROR(H5E_ERROR, H5E_CANTINIT, FAIL, \"error message initialization failed\");\n";
print HEADER " "x(0*$indent),"if((${name}_g = H5I_register(H5I_ERROR_MSG, msg, true))<0)\n";
for $name (sort @{$section_list{$sect_name}}) {
print HEADER "/* $name */\n";
print HEADER " "x(0*$indent),"assert(H5I_INVALID_HID == ${name}_g);\n";
print HEADER " "x(0*$indent),"if((${name}_g = H5I_register(H5I_ERROR_MSG, &${name}_msg_s, false)) < 0)\n";
print HEADER " "x(1*$indent),"HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, \"can't register error message\");\n";
if ($first_minor == 0) {
@ -319,25 +396,25 @@ sub create_term ($) {
# Iterate over all the major errors
print HEADER "\n/* Reset major error IDs */\n";
foreach $name (keys %major) {
print HEADER " "x($indent),"\n${name}_g=";
foreach $name (sort keys %major) {
print HEADER " "x($indent),"${name}_g =\n";
}
print HEADER " H5I_INVALID_HID;\n";
print HEADER " "x(0*$indent),"H5E_first_maj_id_g = H5I_INVALID_HID;\n\n";
print HEADER " "x(2*$indent),"H5I_INVALID_HID;\n";
print HEADER "\n"," "x(0*$indent),"H5E_first_maj_id_g = H5I_INVALID_HID;\n";
print HEADER " "x(0*$indent),"H5E_last_maj_id_g = H5I_INVALID_HID;\n\n";
# Iterate over all the minor error sections
print HEADER "\n/* Reset minor error IDs */\n";
while ( ($sect_name, $sect_desc) = each (%section)) {
print HEADER "\n"," "x(0*$indent),"\n/* $sect_desc */";
foreach $sect_name (sort keys %section) {
print HEADER "\n/* $sect_name: $section{$sect_name} */\n";
# Iterate over all the minor errors in each section
for $name ( @{$section_list{$sect_name}}) {
print HEADER " "x($indent),"\n${name}_g=";
for $name (sort @{$section_list{$sect_name}}) {
print HEADER " "x($indent),"${name}_g =\n";
}
}
print HEADER " H5I_INVALID_HID;\n";
print HEADER " "x(0*$indent),"H5E_first_min_id_g = H5I_INVALID_HID;\n\n";
print HEADER " "x(2*$indent),"H5I_INVALID_HID;\n";
print HEADER "\n"," "x(0*$indent),"H5E_first_min_id_g = H5I_INVALID_HID;\n";
print HEADER " "x(0*$indent),"H5E_last_min_id_g = H5I_INVALID_HID;\n\n";
print_endprotect(*HEADER, $file);
@ -356,6 +433,7 @@ sub create_define ($) {
my $desc; # Description of error message
my $sect_name; # Section of minor error messages
my $sect_desc; # Description of section
my $num_msg; # Number of messages
# Rename previous file
# rename "${prefix}${file}", "${prefix}${file}~" or die "unable to make backup";
@ -370,21 +448,29 @@ sub create_define ($) {
print_startprotect(*HEADER, $file);
# Iterate over all the major errors
$num_msg = 0;
print HEADER "\n/* Major error IDs */\n";
foreach $name (keys %major) {
printf HEADER "hid_t %-20s = FAIL; /* %s */\n","${name}_g",$major{$name};
foreach $name (sort keys %major) {
printf HEADER "hid_t %-20s = H5I_INVALID_HID; /* %s */\n","${name}_g",$major{$name};
$num_msg++;
}
print HEADER "\n/* Number of major error messages */\n";
printf HEADER "#define H5E_NUM_MAJ_ERRORS %d\n", $num_msg;
# Iterate over all the minor error sections
$num_msg = 0;
print HEADER "\n/* Minor error IDs */\n";
while ( ($sect_name, $sect_desc) = each (%section)) {
print HEADER "\n/* $sect_desc */\n";
foreach $sect_name (sort keys %section) {
print HEADER "\n/* $sect_name: $section{$sect_name} */\n";
# Iterate over all the minor errors in each section
for $name ( @{$section_list{$sect_name}}) {
printf HEADER "hid_t %-20s = FAIL; /* %s */\n","${name}_g",$minor{$name};
for $name (sort @{$section_list{$sect_name}}) {
printf HEADER "hid_t %-20s = H5I_INVALID_HID; /* %s */\n","${name}_g",$minor{$name};
$num_msg++;
}
}
print HEADER "\n/* Number of minor error messages */\n";
printf HEADER "#define H5E_NUM_MIN_ERRORS %d\n", $num_msg;
print_endprotect(*HEADER, $file);
@ -409,10 +495,14 @@ for $file (@ARGV) {
}
}
close SOURCE;
# Create header files
print "Generating 'H5Epubgen.h'\n";
create_public($prefix);
print "Generating 'H5Emajdef.h'\n";
create_majdef($prefix);
print "Generating 'H5Emindef.h'\n";
create_mindef($prefix);
print "Generating 'H5Einit.h'\n";
create_init($prefix);
print "Generating 'H5Eterm.h'\n";

View File

@ -870,6 +870,8 @@ set (H5_PRIVATE_HEADERS
${HDF5_SRC_DIR}/H5Edefin.h
${HDF5_SRC_DIR}/H5Einit.h
${HDF5_SRC_DIR}/H5Emajdef.h
${HDF5_SRC_DIR}/H5Emindef.h
${HDF5_SRC_DIR}/H5Epkg.h
${HDF5_SRC_DIR}/H5Eprivate.h
${HDF5_SRC_DIR}/H5Eterm.h

View File

@ -2137,7 +2137,7 @@ H5Dformat_convert(hid_t dset_id)
/* Convert the dataset */
if (H5VL_dataset_optional(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0)
HGOTO_ERROR(H5E_DATASET, H5E_INTERNAL, FAIL, "can't convert dataset format");
HGOTO_ERROR(H5E_DATASET, H5E_CANTUPDATE, FAIL, "can't convert dataset format");
done:
FUNC_LEAVE_API(ret_value)
@ -2442,7 +2442,7 @@ H5Dchunk_iter(hid_t dset_id, hid_t dxpl_id, H5D_chunk_iter_op_t op, void *op_dat
/* Iterate over the chunks */
if ((ret_value = H5VL_dataset_optional(vol_obj, &vol_cb_args, dxpl_id, H5_REQUEST_NULL)) < 0)
HERROR(H5E_BADITER, H5E_BADITER, "error iterating over dataset chunks");
HERROR(H5E_DATASET, H5E_BADITER, "error iterating over dataset chunks");
done:
FUNC_LEAVE_API(ret_value)

View File

@ -1495,7 +1495,7 @@ H5D_open(const H5G_loc_t *loc, hid_t dapl_id)
/* Check if dataset was already open */
if (NULL == (shared_fo = (H5D_shared_t *)H5FO_opened(dataset->oloc.file, dataset->oloc.addr))) {
/* Clear any errors from H5FO_opened() */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Open the dataset object */
if (H5D__open_oid(dataset, dapl_id) < 0)

View File

@ -884,7 +884,7 @@ H5D__virtual_open_source_dset(const H5D_t *vdset, H5O_storage_virtual_ent_t *vir
src_file_open = true;
else
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
} /* end if */
else
/* Source file is ".", use the virtual dataset's file */
@ -906,7 +906,7 @@ H5D__virtual_open_source_dset(const H5D_t *vdset, H5O_storage_virtual_ent_t *vir
/* Dataset does not exist */
if (NULL == source_dset->dset) {
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
source_dset->dset_exists = false;
} /* end if */

873
src/H5E.c

File diff suppressed because it is too large Load Diff

View File

@ -182,13 +182,29 @@ done:
herr_t
H5Epush1(const char *file, const char *func, unsigned line, H5E_major_t maj, H5E_minor_t min, const char *str)
{
herr_t ret_value = SUCCEED; /* Return value */
const char *tmp_file; /* Copy of the file name */
const char *tmp_func; /* Copy of the function name */
herr_t ret_value = SUCCEED; /* Return value */
/* Don't clear the error stack! :-) */
FUNC_ENTER_API_NOCLEAR(FAIL)
/* Duplicate string information */
if (NULL == (tmp_file = strdup(file)))
HGOTO_ERROR(H5E_ERROR, H5E_CANTALLOC, FAIL, "can't duplicate file string");
if (NULL == (tmp_func = strdup(func)))
HGOTO_ERROR(H5E_ERROR, H5E_CANTALLOC, FAIL, "can't duplicate function string");
/* Increment refcount on non-library IDs */
if (maj < H5E_first_maj_id_g || maj > H5E_last_maj_id_g)
if (H5I_inc_ref(maj, false) < 0)
HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "can't increment major error ID");
if (min < H5E_first_min_id_g || min > H5E_last_min_id_g)
if (H5I_inc_ref(min, false) < 0)
HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "can't increment minor error ID");
/* Push the error on the default error stack */
if (H5E__push_stack(NULL, file, func, line, H5E_ERR_CLS_g, maj, min, str) < 0)
if (H5E__push_stack(NULL, true, tmp_file, tmp_func, line, H5E_ERR_CLS_g, maj, min, str, NULL) < 0)
HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't push error on stack");
done:
@ -214,7 +230,7 @@ H5Eclear1(void)
FUNC_ENTER_API_NOCLEAR(FAIL)
/* Clear the default error stack */
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack");
done:
@ -237,8 +253,8 @@ done:
herr_t
H5Eprint1(FILE *stream)
{
H5E_t *estack; /* Error stack to operate on */
herr_t ret_value = SUCCEED; /* Return value */
H5E_stack_t *estack; /* Error stack to operate on */
herr_t ret_value = SUCCEED; /* Return value */
/* Don't clear the error stack! :-) */
FUNC_ENTER_API_NOCLEAR(FAIL)
@ -268,7 +284,7 @@ done:
herr_t
H5Ewalk1(H5E_direction_t direction, H5E_walk1_t func, void *client_data)
{
H5E_t *estack; /* Error stack to operate on */
H5E_stack_t *estack; /* Error stack to operate on */
H5E_walk_op_t walk_op; /* Error stack walking callback */
herr_t ret_value = SUCCEED; /* Return value */
@ -304,7 +320,7 @@ done:
herr_t
H5Eget_auto1(H5E_auto1_t *func /*out*/, void **client_data /*out*/)
{
H5E_t *estack; /* Error stack to operate on */
H5E_stack_t *estack; /* Error stack to operate on */
H5E_auto_op_t auto_op; /* Error stack operator */
herr_t ret_value = SUCCEED; /* Return value */
@ -352,7 +368,7 @@ done:
herr_t
H5Eset_auto1(H5E_auto1_t func, void *client_data)
{
H5E_t *estack; /* Error stack to operate on */
H5E_stack_t *estack; /* Error stack to operate on */
H5E_auto_op_t auto_op; /* Error stack operator */
herr_t ret_value = SUCCEED; /* Return value */

File diff suppressed because it is too large Load Diff

View File

@ -34,8 +34,8 @@
/* Amount to indent each error */
#define H5E_INDENT 2
/* Number of slots in an error stack */
#define H5E_NSLOTS 32
/* Number of entries in an error stack */
#define H5E_MAX_ENTRIES 32
#ifdef H5_HAVE_THREADSAFE
/*
@ -45,7 +45,7 @@
* be handled by the pthread library.
*
* In order for this macro to work, H5E__get_my_stack() must be preceded
* by "H5E_t *estack =".
* by "H5E_stack_t *estack =".
*/
#define H5E__get_my_stack() H5E__get_stack()
#else /* H5_HAVE_THREADSAFE */
@ -88,25 +88,33 @@ typedef struct {
/* Error class */
typedef struct H5E_cls_t {
char *cls_name; /* Name of error class */
char *lib_name; /* Name of library within class */
char *lib_vers; /* Version of library */
bool app_cls; /* Whether the class came from app */
const char *cls_name; /* Name of error class */
const char *lib_name; /* Name of library within class */
const char *lib_vers; /* Version of library */
} H5E_cls_t;
/* Major or minor message */
typedef struct H5E_msg_t {
char *msg; /* Message for error */
H5E_type_t type; /* Type of error (major or minor) */
H5E_cls_t *cls; /* Which error class this message belongs to */
bool app_msg; /* Whether the message came from app */
const char *msg; /* Message for error */
H5E_type_t type; /* Type of error (major or minor) */
const H5E_cls_t *cls; /* Which error class this message belongs to */
} H5E_msg_t;
/* Error stack entry */
typedef struct H5E_entry_t {
bool app_entry; /* Whether the entry came from app */
H5E_error2_t err; /* Error entry */
} H5E_entry_t;
/* Error stack */
struct H5E_t {
size_t nused; /* Num slots currently used in stack */
H5E_error2_t slot[H5E_NSLOTS]; /* Array of error records */
H5E_auto_op_t auto_op; /* Operator for 'automatic' error reporting */
void *auto_data; /* Callback data for 'automatic error reporting */
};
typedef struct H5E_stack_t {
size_t nused; /* Num entries currently on stack */
H5E_entry_t entries[H5E_MAX_ENTRIES]; /* Array of error entries */
H5E_auto_op_t auto_op; /* Operator for 'automatic' error reporting */
void *auto_data; /* Callback data for 'automatic error reporting */
} H5E_stack_t;
/*****************************/
/* Package Private Variables */
@ -116,7 +124,7 @@ struct H5E_t {
/*
* The current error stack.
*/
H5_DLLVAR H5E_t H5E_stack_g[1];
H5_DLLVAR H5E_stack_t H5E_stack_g[1];
#endif
/* First & last major and minor error codes registered by the library */
@ -128,20 +136,28 @@ H5_DLLVAR hid_t H5E_last_min_id_g;
/******************************/
/* Package Private Prototypes */
/******************************/
H5_DLL herr_t H5E__term_deprec_interface(void);
#ifdef H5_HAVE_THREADSAFE
H5_DLL H5E_t *H5E__get_stack(void);
H5_DLL H5E_stack_t *H5E__get_stack(void);
#endif /* H5_HAVE_THREADSAFE */
H5_DLL herr_t H5E__push_stack(H5E_t *estack, const char *file, const char *func, unsigned line, hid_t cls_id,
hid_t maj_id, hid_t min_id, const char *desc);
H5_DLL herr_t H5E__set_stack_entry(H5E_error2_t *err_entry, const char *file, const char *func, unsigned line,
hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc);
H5_DLL ssize_t H5E__get_msg(const H5E_msg_t *msg_ptr, H5E_type_t *type, char *msg, size_t size);
H5_DLL herr_t H5E__print(const H5E_t *estack, FILE *stream, bool bk_compat);
H5_DLL herr_t H5E__walk(const H5E_t *estack, H5E_direction_t direction, const H5E_walk_op_t *op,
void *client_data);
H5_DLL herr_t H5E__get_auto(const H5E_t *estack, H5E_auto_op_t *op, void **client_data);
H5_DLL herr_t H5E__set_auto(H5E_t *estack, const H5E_auto_op_t *op, void *client_data);
H5_DLL herr_t H5E__pop(H5E_t *err_stack, size_t count);
H5_DLL H5E_cls_t *H5E__register_class(const char *cls_name, const char *lib_name, const char *version);
H5_DLL ssize_t H5E__get_class_name(const H5E_cls_t *cls, char *name, size_t size);
H5_DLL H5E_msg_t *H5E__create_msg(H5E_cls_t *cls, H5E_type_t msg_type, const char *msg);
H5_DLL ssize_t H5E__get_msg(const H5E_msg_t *msg_ptr, H5E_type_t *type, char *msg, size_t size);
H5_DLL void H5E__set_default_auto(H5E_stack_t *stk);
H5_DLL H5E_stack_t *H5E__get_current_stack(void);
H5_DLL herr_t H5E__set_current_stack(H5E_stack_t *estack);
H5_DLL ssize_t H5E__get_num(const H5E_stack_t *err_stack);
H5_DLL herr_t H5E__push_stack(H5E_stack_t *estack, bool app_entry, const char *file, const char *func,
unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt,
va_list *ap);
H5_DLL herr_t H5E__print(const H5E_stack_t *estack, FILE *stream, bool bk_compat);
H5_DLL herr_t H5E__print2(hid_t err_stack, FILE *stream);
H5_DLL herr_t H5E__walk(const H5E_stack_t *estack, H5E_direction_t direction, const H5E_walk_op_t *op,
void *client_data);
H5_DLL herr_t H5E__get_auto(const H5E_stack_t *estack, H5E_auto_op_t *op, void **client_data);
H5_DLL herr_t H5E__set_auto(H5E_stack_t *estack, const H5E_auto_op_t *op, void *client_data);
H5_DLL herr_t H5E__pop(H5E_stack_t *err_stack, size_t count);
H5_DLL herr_t H5E__append_stack(H5E_stack_t *dst_estack, const H5E_stack_t *src_stack);
H5_DLL herr_t H5E__clear_stack(H5E_stack_t *estack);
#endif /* H5Epkg_H */

View File

@ -21,9 +21,6 @@
/* Private headers needed by this file */
#include "H5private.h"
/* Typedef for error stack (defined in H5Epkg.h) */
typedef struct H5E_t H5E_t;
/*
* HERROR macro, used to facilitate error reporting between a FUNC_ENTER()
* and a FUNC_LEAVE() within a function body. The arguments are the major
@ -31,7 +28,7 @@ typedef struct H5E_t H5E_t;
*/
#define HERROR(maj_id, min_id, ...) \
do { \
H5E_printf_stack(NULL, __FILE__, __func__, __LINE__, H5E_ERR_CLS_g, maj_id, min_id, __VA_ARGS__); \
H5E_printf_stack(__FILE__, __func__, __LINE__, maj_id, min_id, __VA_ARGS__); \
} while (0)
/*
@ -185,9 +182,9 @@ extern int H5E_mpi_error_str_len;
/* Library-private functions defined in H5E package */
H5_DLL herr_t H5E_init(void);
H5_DLL herr_t H5E_printf_stack(H5E_t *estack, const char *file, const char *func, unsigned line, hid_t cls_id,
hid_t maj_id, hid_t min_id, const char *fmt, ...) H5_ATTR_FORMAT(printf, 8, 9);
H5_DLL herr_t H5E_clear_stack(H5E_t *estack);
H5_DLL herr_t H5E_printf_stack(const char *file, const char *func, unsigned line, hid_t maj_idx,
hid_t min_idx, const char *fmt, ...) H5_ATTR_FORMAT(printf, 6, 7);
H5_DLL herr_t H5E_clear_stack(void);
H5_DLL herr_t H5E_dump_api_stack(void);
#endif /* H5Eprivate_H */

View File

@ -779,7 +779,7 @@ H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxad
if (!file->memb[file->nmembs]) {
if (0 == file->nmembs)
HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open member file");
H5E_clear_stack(NULL);
H5E_clear_stack();
break;
}
file->nmembs++;
@ -1497,7 +1497,7 @@ H5FD__family_delete(const char *filename, hid_t fapl_id)
if (0 == current_member)
HGOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL, "unable to delete member file");
else
H5E_clear_stack(NULL);
H5E_clear_stack();
break;
}
current_member++;

View File

@ -468,7 +468,7 @@ H5FD__onion_commit_new_revision_record(H5FD_onion_t *file)
if ((true == file->is_open_rw) && (H5FD__onion_merge_revision_index_into_archival_index(
file->rev_index, &file->curr_rev_record.archival_index) < 0))
HGOTO_ERROR(H5E_VFL, H5E_INTERNAL, FAIL, "unable to update index to write");
HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "unable to update index to write");
if (NULL == (buf = H5MM_malloc(H5FD_ONION_ENCODED_SIZE_REVISION_RECORD + (size_t)rec->comment_size +
(H5FD_ONION_ENCODED_SIZE_INDEX_ENTRY * rec->archival_index.n_entries))))

View File

@ -859,7 +859,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
char *ptr;
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Get last component of file_name */
H5_GET_LAST_DELIMITER(file_name, ptr)
@ -880,7 +880,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
/* Adjust temporary file name if file not opened */
if (NULL == src_file) {
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Strip "<drive-letter>:" */
strncpy(temp_file_name, &file_name[2], temp_file_name_len);
@ -928,11 +928,11 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
/* Check for file not opened */
if (NULL == src_file)
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Leave if file was opened */
else
break;
H5E_clear_stack(NULL);
H5E_clear_stack();
} /* end if */
} /* end while */
@ -955,7 +955,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
/* Check for file not opened */
if (NULL == src_file)
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
} /* end if */
/* Try searching from main file's "extpath": see description in H5F_open() & H5_build_extpath() */
@ -976,7 +976,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
/* Check for file not opened */
if (NULL == src_file)
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
} /* end if */
} /* end if */
@ -988,7 +988,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
/* Check for file not opened */
if (NULL == src_file)
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
} /* end if */
/* try the 'resolved' name for the virtual file */
@ -1019,7 +1019,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, const c
/* Check for file not opened */
if (NULL == src_file)
/* Reset the error stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
} /* end if */
/* Set return value (possibly NULL or valid H5F_t *) */
@ -1893,7 +1893,7 @@ H5F_open(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id)
*/
if ((tent_flags == flags) || (lf == NULL)) {
if (tent_flags != flags) {
H5E_clear_stack(NULL);
H5E_clear_stack();
tent_flags = flags;
}

View File

@ -439,7 +439,7 @@ H5G_open(const H5G_loc_t *loc)
if ((shared_fo = (H5G_shared_t *)H5FO_opened(grp->oloc.file, grp->oloc.addr)) == NULL) {
/* Clear any errors from H5FO_opened() */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Open the group object */
if (H5G__open_oid(grp) < 0)

View File

@ -591,7 +591,7 @@ H5G__loc_exists_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc /*in*/, const char H5_ATTR_
if (lnk)
*exists = false;
else
HGOTO_ERROR(H5E_SYM, H5E_INTERNAL, FAIL, "no object or link info?");
HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "no object or link info?");
else
*exists = true;

View File

@ -1428,7 +1428,7 @@ H5G_node_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, had
if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) {
H5G_bt_common_t udata; /*data to pass through B-tree */
H5E_clear_stack(NULL); /* discard that error */
H5E_clear_stack(); /* discard that error */
udata.heap = heap;
udata.block_size = H5HL_heap_get_size(heap);
if (H5B_debug(f, addr, stream, indent, fwidth, H5B_SNODE, &udata) < 0)

View File

@ -999,7 +999,7 @@ H5G__stab_valid(H5O_loc_t *grp_oloc, H5O_stab_t *alt_stab)
/* Update the symbol table message and clear errors if necessary */
if (changed) {
H5E_clear_stack(NULL);
H5E_clear_stack();
if (H5O_msg_write(grp_oloc, H5O_STAB_ID, 0, H5O_UPDATE_TIME | H5O_UPDATE_FORCE, &stab) < 0)
HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to correct symbol table message");
} /* end if */

View File

@ -199,7 +199,7 @@ H5G__traverse_ud(const H5G_loc_t *grp_loc /*in,out*/, const H5O_link_t *lnk, H5G
/* Check if we just needed to know if the object exists */
if (target & H5G_TARGET_EXISTS) {
/* Clear any errors from the stack */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Indicate that the object doesn't exist */
*obj_exists = false;

View File

@ -1230,27 +1230,6 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5I_dec_app_ref_always_close_async() */
/*-------------------------------------------------------------------------
* Function: H5I_do_inc_ref
*
* Purpose: Helper function for H5I_inc_ref/H5I_inc_ref_noherr to
* actually increment the reference count for an object.
*
* Return: The new reference count (can't fail)
*
*-------------------------------------------------------------------------
*/
static inline int
H5I_do_inc_ref(H5I_id_info_t *info, bool app_ref)
{
/* Adjust reference counts */
++(info->count);
if (app_ref)
++(info->app_count);
return (int)(app_ref ? info->app_count : info->count);
}
/*-------------------------------------------------------------------------
* Function: H5I_inc_ref
*
@ -1276,59 +1255,18 @@ H5I_inc_ref(hid_t id, bool app_ref)
if (NULL == (info = H5I__find_id(id)))
HGOTO_ERROR(H5E_ID, H5E_BADID, (-1), "can't locate ID");
/* Adjust reference counts */
++(info->count);
if (app_ref)
++(info->app_count);
/* Set return value */
ret_value = H5I_do_inc_ref(info, app_ref);
ret_value = (int)(app_ref ? info->app_count : info->count);
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5I_inc_ref() */
/*-------------------------------------------------------------------------
* Function: H5I_inc_ref_noherr
*
* Purpose: Increment the reference count for an object. Exactly like
* H5I_inc_ref, except that it makes use of HGOTO_DONE on
* failure instead of HGOTO_ERROR. This function is
* specifically meant to be used in the H5E package, where we
* have to avoid calling any function or macro that may call
* HGOTO_ERROR and similar. Otherwise, we can cause a stack
* overflow that looks like (for example):
*
* H5E_printf_stack()
* H5E__push_stack()
* H5I_inc_ref()
* H5I__find_id() (FAIL)
* HGOTO_ERROR()
* H5E_printf_stack()
* ...
*
* Return: Success: The new reference count
* Failure: -1
*
*-------------------------------------------------------------------------
*/
int
H5I_inc_ref_noherr(hid_t id, bool app_ref)
{
H5I_id_info_t *info = NULL; /* Pointer to the ID info */
int ret_value = 0; /* Return value */
FUNC_ENTER_NOAPI_NOERR
/* Sanity check */
assert(id >= 0);
/* General lookup of the ID */
if (NULL == (info = H5I__find_id(id)))
HGOTO_DONE((-1));
/* Set return value */
ret_value = H5I_do_inc_ref(info, app_ref);
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5I_inc_ref_noherr() */
/*-------------------------------------------------------------------------
* Function: H5I_get_ref
*

View File

@ -68,7 +68,6 @@ H5_DLL H5I_type_t H5I_get_type(hid_t id);
H5_DLL herr_t H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, bool app_ref);
H5_DLL int H5I_get_ref(hid_t id, bool app_ref);
H5_DLL int H5I_inc_ref(hid_t id, bool app_ref);
H5_DLL int H5I_inc_ref_noherr(hid_t id, bool app_ref);
H5_DLL int H5I_dec_ref(hid_t id);
H5_DLL int H5I_dec_app_ref(hid_t id);
H5_DLL int H5I_dec_app_ref_async(hid_t id, void **token);

View File

@ -1468,7 +1468,7 @@ H5O__copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst /*i
if (H5G_loc_find(&dst_root_loc, suggestion->path, &obj_loc /*out*/) < 0)
/* Ignore errors - i.e. suggestions not present in
* destination file */
H5E_clear_stack(NULL);
H5E_clear_stack();
else
/* Check object and add to skip list if appropriate */
if (H5O__copy_search_comm_dt_check(&obj_oloc, &udata) < 0) {

View File

@ -1601,7 +1601,7 @@ H5O__obj_type_real(const H5O_t *oh, H5O_type_t *obj_type)
/* Look up class for object header */
if (NULL == (obj_class = H5O__obj_class_real(oh))) {
/* Clear error stack from "failed" class lookup */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Set type to "unknown" */
*obj_type = H5O_TYPE_UNKNOWN;

View File

@ -944,7 +944,7 @@ H5SM_can_share(H5F_t *f, H5SM_master_table_t *table, ssize_t *sohm_index_num, un
* then this type of message isn't shareable
*/
if ((index_num = H5SM__get_index(my_table, type_id)) < 0) {
H5E_clear_stack(NULL); /*ignore error*/
H5E_clear_stack(); /*ignore error*/
HGOTO_DONE(false);
} /* end if */
@ -1337,9 +1337,9 @@ H5SM__write_mesg(H5F_t *f, H5O_t *open_oh, H5SM_index_header_t *header, bool def
found = true;
} /* end if */
else
H5E_clear_stack(NULL); /*ignore error*/
} /* end else */
} /* end else */
H5E_clear_stack(); /*ignore error*/
} /* end else */
} /* end else */
if (found) {
/* If the message was found, it's shared in the heap (now). Set up a

View File

@ -2727,14 +2727,14 @@ H5T__register(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst, H5T_con
"unable to decrement reference count on temporary ID");
tmp_sid = tmp_did = H5I_INVALID_HID;
tmp_stype = tmp_dtype = NULL;
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to clear current error stack");
continue;
} /* end if */
} /* end if */
else if ((conv->u.lib_func)(old_path->src, old_path->dst, &cdata, &conv_ctx, 0, 0, 0, NULL,
NULL) < 0) {
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to clear current error stack");
continue;
} /* end if */
@ -2776,7 +2776,7 @@ H5T__register(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst, H5T_con
}
/* We don't care about any failures during the freeing process */
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to clear current error stack");
} /* end for */
} /* end else */
@ -3891,7 +3891,7 @@ H5T_copy_reopen(H5T_t *old_dt)
if (NULL ==
(reopened_fo = (H5T_shared_t *)H5FO_opened(old_dt->sh_loc.file, old_dt->sh_loc.u.loc.oh_addr))) {
/* Clear any errors from H5FO_opened() */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Open named datatype again */
if (H5O_open(&old_dt->oloc) < 0)
@ -5298,7 +5298,7 @@ H5T__init_path_table(void)
fprintf(H5DEBUG(T), "H5T: unable to initialize no-op conversion function (ignored)\n");
#endif
/* Ignore any errors from the conversion function */
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to clear current error stack");
} /* end if */
@ -5431,7 +5431,7 @@ H5T__path_find_init_new_path(H5T_path_t *path, const H5T_t *src, const H5T_t *ds
if (status < 0) {
memset(&(path->cdata), 0, sizeof(H5T_cdata_t));
/* ignore the error */
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
HGOTO_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to clear current error stack");
path_init_error = true;
}
@ -5516,7 +5516,7 @@ H5T__path_free(H5T_path_t *path, H5T_conv_ctx_t *conv_ctx)
if (status < 0) {
/* Ignore any error from shutting down the path */
if (H5E_clear_stack(NULL) < 0)
if (H5E_clear_stack() < 0)
/* Push error, but keep going */
HDONE_ERROR(H5E_DATATYPE, H5E_CANTRESET, FAIL, "unable to clear current error stack");

View File

@ -1037,7 +1037,7 @@ H5T_open(const H5G_loc_t *loc)
/* Check if datatype was already open */
if (NULL == (shared_fo = (H5T_shared_t *)H5FO_opened(loc->oloc->file, loc->oloc->addr))) {
/* Clear any errors from H5FO_opened() */
H5E_clear_stack(NULL);
H5E_clear_stack();
/* Open the datatype object */
if (NULL == (dt = H5T__open_oid(loc)))

View File

@ -3806,7 +3806,7 @@ H5VL_file_open(H5VL_connector_prop_t *connector_prop, const char *name, unsigned
* Otherwise, if no VOL connectors are available, throw
* error from original file open failure.
*/
H5E_clear_stack(NULL);
H5E_clear_stack();
if (NULL == (ret_value = H5VL__file_open(find_connector_ud.cls, name, flags,
find_connector_ud.fapl_id, dxpl_id, req)))

View File

@ -781,7 +781,7 @@ H5Z__prelude_callback(const H5O_pline_t *pline, hid_t dcpl_id, hid_t type_id, hi
if (NULL == (fclass = H5Z_find(pline->filter[u].id))) {
/* Ignore errors from optional filters */
if (pline->filter[u].flags & H5Z_FLAG_OPTIONAL)
H5E_clear_stack(NULL);
H5E_clear_stack();
else
HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "required filter was not located");
} /* end if */
@ -1448,7 +1448,7 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i
*nbytes = *buf_size;
failed |= (unsigned)1 << idx;
H5E_clear_stack(NULL);
H5E_clear_stack();
}
else
*nbytes = new_nbytes;
@ -1465,7 +1465,7 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i
if ((pline->filter[idx].flags & H5Z_FLAG_OPTIONAL) == 0)
HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "required filter is not registered");
failed |= (unsigned)1 << idx;
H5E_clear_stack(NULL);
H5E_clear_stack();
continue; /* filter excluded */
} /* end if */
@ -1501,7 +1501,7 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i
*nbytes = *buf_size;
}
failed |= (unsigned)1 << idx;
H5E_clear_stack(NULL);
H5E_clear_stack();
}
else
*nbytes = new_nbytes;

View File

@ -1265,7 +1265,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props);
FUNC_ENTER_API_INIT(err); \
FUNC_ENTER_API_PUSH(err); \
/* Clear thread error stack entering public functions */ \
H5E_clear_stack(NULL); \
H5E_clear_stack(); \
{
/*

View File

@ -88,6 +88,10 @@
* For pre-releases like \c snap0. Empty string for official releases.
*/
#define H5_VERS_SUBRELEASE ""
/**
* Short version string
*/
#define H5_VERS_STR "1.15.0"
/**
* Full version string
*/

View File

@ -182,9 +182,9 @@ settings_DATA=libhdf5.settings
# Error header generation
#
# Actually, H5Einit.h, H5Eterm.h, H5Edefin.h and H5Epubgen.h all
# depend on H5err.txt, but the perl script generates them all, so just
# list one here.
# Actually, H5Einit.h, H5Eterm.h, H5Edefin.h, H5Emajdef.h, H5Emindef.h,
# and H5Epubgen.h all depend on H5err.txt, but the perl script generates them
# all, so just list one here.
$(top_srcdir)/src/H5Edefin.h: $(top_srcdir)/src/H5err.txt
perl $(top_srcdir)/bin/make_err $?