gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 2814c1e8: Makefile extensions: sanity checks a


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 2814c1e8: Makefile extensions: sanity checks added to ast-text-prev functions
Date: Tue, 16 Apr 2024 14:51:23 -0400 (EDT)

branch: master
commit 2814c1e807f09045b57ba0700502789d9ff466bc
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Makefile extensions: sanity checks added to ast-text-prev functions
    
    Until now, when any of the 'ast-text-prev*' functions were given an empty
    string for their argument, they would produce a segmentation fault (because
    they were reading from a non-allocated string!).
    
    With this commit, a sanity check function has been added at the start of
    all Gnuastro's Makefile extension functions. It will return an empty string
    when any of the input arguments is an empty string.
---
 doc/gnuastro.texi |   8 ++--
 lib/makeplugin.c  | 140 +++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 102 insertions(+), 46 deletions(-)

diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index fbe2c297..748d0893 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -35934,8 +35934,8 @@ For example, the following minimal Makefile will print 
@code{fooo baar uggh} wor
 load /usr/local/lib/libgnuastro_make.so
 
 list  = fOOo bAar UggH
-list := $(ast-text-to-lower $(list))
-all:; echo $(ulist)
+llist := $(ast-text-to-lower $(list))
+all:; echo $(llist)
 @end example
 
 
@@ -35971,6 +35971,7 @@ all:
 @item $(ast-text-prev TARGET, LIST)
 Returns the word in @code{LIST} that is previous to @code{TARGET}.
 If @code{TARGET} is the first word of the list, or is not within it at all, 
this function will return an empty string (nothing).
+If any of the arguments are an empty string (or only contain space characters 
like `@key{SPACE}', `@key{TAB}', new-line and etc), this function will return 
an empty string (having no effect in Make).
 
 One scenario when this function can be useful is when you want a list of 
higher-level targets to always be executed in sequence (even when Make is run 
in parallel).
 But you want their lower-level prerequisites to be executed in parallel.
@@ -36023,6 +36024,7 @@ Unfortunately the @code{.NOTPARALLEL} target of GNU 
Make doesn't allow this leve
 
 @item $(ast-text-prev-batch TARGET, NUM, LIST)
 Returns the previous batch of @code{NUM} words in @code{LIST} (in relation to 
the batch containing @code{TARGET}).
+If any of the arguments are an empty string (or only contain space characters 
like `@key{SPACE}', `@key{TAB}', new-line and etc), this function will return 
an empty string (having no effect in Make).
 In the special case that @code{NUM=1}, this is equivalent to the 
@code{ast-text-prev} function that is described above.
 
 Here is one scenario where this function is useful: in astronomy datasets are 
can easily be very large.
@@ -36075,7 +36077,7 @@ Any other rule that is later added to this make file 
(as a prerequisite/parent o
 @cindex RAM
 Similar to @code{ast-text-prev-batch}, but instead of taking the number of 
words/files in each batch, this function takes the maximum amount of RAM that 
is needed by one instance of the recipe.
 Through the @code{NEEDED_RAM_GB} argument, you should specify the amount of 
ram that a @emph{single} instance of the recipe in this rule needs.
-If @code{NEEDED_RAM_GB} is an empty string, this function will return an empty 
string (having no effect in your prerequisite list).
+If any of the arguments are an empty string (or only contain space characters 
like `@key{SPACE}', `@key{TAB}', new-line and etc), this function will return 
an empty string (having no effect in Make).
 
 The number of files in each batch is calculated internally by reading the 
available RAM on the system at the moment Make calls this function.
 Therefore this function is more generalizable to different computers (with 
very different RAM and/or CPU threads).
diff --git a/lib/makeplugin.c b/lib/makeplugin.c
index 081311d0..f4e116cb 100644
--- a/lib/makeplugin.c
+++ b/lib/makeplugin.c
@@ -72,6 +72,47 @@ static char 
*fits_unique_keyvalues_name=MAKEPLUGIN_FUNC_PREFIX"-fits-unique-keyv
 
 
 
+/**********************************************************************/
+/***************            Internal functions          ***************/
+/**********************************************************************/
+/* Return 1 if there is a problem. */
+static int
+makeplugin_sanity_check(char **argv, size_t num)
+{
+  char *c;
+  size_t i;
+
+  /* In case any of the arguments are an empty string (only containing the
+     C locale space characters identified with 'isspace'), then just return
+     an empty string. */
+  for(i=0;i<num;++i)
+    {
+      for(c=argv[i]; c!=NULL && *c!='\0'; ++c) if(!isspace(*c)) break;
+      if(*c=='\0') return 1; /* When the string is only "space". */
+    }
+
+  /* All checks passed, everything is good. */
+  return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 /**********************************************************************/
 /***************          Configuration function        ***************/
@@ -80,11 +121,14 @@ static char *
 makeplugin_version_is(const char *caller, unsigned int argc, char **argv)
 {
   int check=0;
-  char *out=NULL;
-  char *version=gal_txt_trim_space(argv[0]);
+  char *version, *out=NULL;
+
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 1)) return NULL;
 
   /* If the version matches, set the value of 'check'. */
-  if( version && !strcmp(PACKAGE_VERSION, version) ) check=1;
+  version=gal_txt_trim_space(argv[0]);
+  if( !strcmp(PACKAGE_VERSION, version) ) check=1;
 
   /* Write the value into the 'out' pointer. */
   if( asprintf(&out, "%d", check)<0 )
@@ -124,11 +168,14 @@ static char *
 makeplugin_text_contains_base(char **argv, int has1_not0)
 {
   char *out=NULL;
-  gal_list_str_t *tmp, *outlist=NULL;
+  gal_list_str_t *tmp, *strings, *outlist=NULL;
   char *match=argv[0]; /* No trimming the white space before/after, as in */
-  gal_list_str_t *strings=gal_list_str_extract(argv[1]); /* Make itself.  */
+
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 2)) return NULL;
 
   /* Parse the input strings and find the ones that match. */
+  strings=gal_list_str_extract(argv[1]);
   for(tmp=strings; tmp!=NULL; tmp=tmp->next)
     if( gal_txt_contains_string(tmp->v, match)==has1_not0 )
       gal_list_str_add(&outlist, tmp->v, 0);
@@ -184,6 +231,11 @@ makeplugin_text_to_upper(const char *caller, unsigned int 
argc,
                          char **argv)
 {
   char *out;
+
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 1)) return NULL;
+
+  /* Main operation. */
   gal_checkset_allocate_copy(argv[0], &out);
   gal_checkset_string_case_change(out, 1);
   return out;
@@ -199,6 +251,11 @@ makeplugin_text_to_lower(const char *caller, unsigned int 
argc,
                          char **argv)
 {
   char *out;
+
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 1)) return NULL;
+
+  /* Main operation. */
   gal_checkset_allocate_copy(argv[0], &out);
   gal_checkset_string_case_change(out, 0);
   return out;
@@ -208,29 +265,6 @@ makeplugin_text_to_lower(const char *caller, unsigned int 
argc,
 
 
 
-/* Return the previous word in the given list. */
-static char *
-makeplugin_text_prev(const char *caller, unsigned int argc, char **argv)
-{
-  int found=0;
-  char *prev=NULL, *target=argv[0];
-  gal_list_str_t *tmp, *list=gal_list_str_extract(argv[1]);
-
-  /* Parse the input list. */
-  for(tmp=list; tmp!=NULL; tmp=tmp->next)
-    {
-      if( strcmp(tmp->v,target) ) prev=tmp->v; /* Not equal. */
-      else {found=1; break;}                   /* Equal.     */
-    }
-
-  /* Return the output. */
-  return found?prev:NULL;
-}
-
-
-
-
-
 /* Given one of the words of the input list, this function will return a
    string containing the previous batch of words. */
 static char *
@@ -324,6 +358,23 @@ makeplugin_text_prev_batch_work(char *target, size_t 
num_in_batch,
 
 
 
+/* Return the previous word in the given list. */
+static char *
+makeplugin_text_prev(const char *caller, unsigned int argc, char **argv)
+{
+  char *target=argv[0], *list=argv[1];
+
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 2)) return NULL;
+
+  /* Parse the input list. */
+  return makeplugin_text_prev_batch_work(target, 1, list);
+}
+
+
+
+
+
 /* Return the previous word in the given list. */
 static char *
 makeplugin_text_prev_batch(const char *caller, unsigned int argc,
@@ -331,13 +382,16 @@ makeplugin_text_prev_batch(const char *caller, unsigned 
int argc,
 {
   size_t num;
   void *nptr;
-  char *target=argv[0], *list=argv[2];
+  char *target=argv[0], *numstr=argv[1], *list=argv[2];
+
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 3)) return NULL;
 
   /* Interpret the number. */
   nptr=&num;
-  if( gal_type_from_string(&nptr, argv[1], GAL_TYPE_SIZE_T) )
+  if( gal_type_from_string(&nptr, numstr, GAL_TYPE_SIZE_T) )
     error(EXIT_SUCCESS, 0, "'%s' could not be read as an "
-          "unsigned integer", argv[1]);
+          "unsigned integer", numstr);
 
   /* Generate the outputs.*/
   return makeplugin_text_prev_batch_work(target, num, list);
@@ -369,20 +423,17 @@ makeplugin_text_prev_batch_by_ram(const char *caller, 
unsigned int argc,
 {
   void *nptr;
   float needed_gb;
-  char *c, *target=argv[0], *list=argv[2];
   size_t num, ram_b=gal_checkset_ram_available(1);
+  char *target=argv[0], *ramstr=argv[1], *list=argv[2];
 
-  /* In case the second argument (Gigabytes) is an empty string (only
-     containing the C locale space characters identified with 'isspace'),
-     then just return an empty string. */
-  for(c=argv[1]; *c!='\0'; ++c) if(!isspace(*c)) break;
-  if(*c=='\0') return NULL; /* Only when the string is only "space". */
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, 3)) return NULL;
 
   /* Interpret the number. */
   nptr=&needed_gb;
-  if( gal_type_from_string(&nptr, argv[1], GAL_TYPE_FLOAT32) )
+  if( gal_type_from_string(&nptr, ramstr, GAL_TYPE_FLOAT32) )
     error(EXIT_SUCCESS, 0, "'%s' could not be read as an "
-          "unsigned integer", argv[1]);
+          "unsigned integer", ramstr);
 
   /* Estimate the number of words in each batch (to be run in parallel if
      this function is used in targets list) and call the final function. */
@@ -420,6 +471,9 @@ makeplugin_fits_check_input(char **argv, size_t numargs, 
char *name)
   char *c;
   size_t i;
 
+  /* Sanity check. */
+  if(makeplugin_sanity_check(argv, numargs)) return 1;
+
   /* If the HDU is empty, print a warning and don't continue. */
   for(i=0;i<numargs;++i)
     {
@@ -430,12 +484,12 @@ makeplugin_fits_check_input(char **argv, size_t numargs, 
char *name)
           if(i>0) /* Message only necessary for first argument. */
             error(EXIT_SUCCESS, 0, "%s: argument %zu is empty",
                   name, i+1);
-          return 0;
+          return 1;
         }
     }
 
   /* If control reaches here, everything is good. */
-  return 1;
+  return 0;
 }
 
 
@@ -458,7 +512,7 @@ makeplugin_fits_with_keyvalue(const char *caller, unsigned 
int argc,
   char *out, *hdu=gal_txt_trim_space(argv[2]);
 
   /* If any of the inputs are empty, then don't bother continuing. */
-  if( makeplugin_fits_check_input(argv, 4, fits_with_keyvalue_name)==0 )
+  if( makeplugin_fits_check_input(argv, 4, fits_with_keyvalue_name) )
     return NULL;
 
   /* Extract the components in the arguments with possibly multiple
@@ -495,7 +549,7 @@ makeplugin_fits_unique_keyvalues(const char *caller, 
unsigned int argc,
   char *out, *hdu=gal_txt_trim_space(argv[1]);
 
   /* If any of the inputs are empty, then don't bother continuing. */
-  if( makeplugin_fits_check_input(argv, 3, fits_unique_keyvalues_name)==0 )
+  if( makeplugin_fits_check_input(argv, 3, fits_unique_keyvalues_name) )
     return NULL;
 
   /* Extract the components in the arguments with possibly multiple



reply via email to

[Prev in Thread] Current Thread [Next in Thread]