Hi Steven,

Thanks for your response. It appears to me that I have offended you with
my last message. Should this be the case, I do apologise, this was not
my intention at all.

On Sun, 2006-07-30 at 19:34 -0400, Steven M. Robbins wrote: 
> Quoting Andree Leidenfrost <[EMAIL PROTECTED]>:
> 
> > Steven, Bruno,
> >
> > Attached please find a patch and demo program for a new function
> > mr_stresc() to properly escape strings for use as arguments with (the
> > likes of) system() and popen().
> >
> > I have thought about using functions like exec() or fork() to avoid
> > system() and popen(). I don't really see how the two latter would be
> > generally evil.
> 
> I never said system() is generally evil and I did not mean to imply  
> that.  Both system() and exec() have their uses, but you need to know  
> *all* the rules in order to use them.  The common pitfall when using  
> system() is that you need to escape the string because it will be  
> interpreted by the shell.  Using exec() is one way to avoid that  
> pitfall.  Doing proper escaping is another, perfectly reasonable  
> solution.
> 
> > To the contrary, e.g. using a function that submits
> > things to 'sh -c' means we have a sane environment like a PATH and so
> > forth.
> 
> Yeah, well ... that depends on whether you can presume the user does  
> have a sane PATH variable.  I'm inclined to believe the opposite,  
> actually.

Interesting territory we are entering here me thinks. Why would you be
inclined to say that something as fundamental as the PATH variable can
not be assumed to be sane?

> > I therefore suggest use of the attached function when calling system()
> > or popen() where required. I believe this is low-risk, low-overhead,
> > little work, a clean approach and can be done bit by bit.
> >
> > What do you say?
> 
> Proper escaping is not impossible, but it is pretty hard due to the  
> arcane syntax of the shell.  However, your previous message implied  
> that the filenames are always passed inside double quotes, and  
> therefore there are exactly three characters that need escaping.

Good point! Quoting using double-quotes is indeed an assumption that I
do make. I should have explicitly said so. (The only other quoting
alternative, i.e. using single quotes is a no-go as it would completely
rule out the use of ' in file names.)

> Since you have a very restricted escaping problem, I agree that  
> escaping is a much easier solution that replacing system() by  
> fork()/exec().

Ok.

> However, your proposed mr_stresc() function has two flaws:
> 
> 1.  New memory is allocated each time so you run the risk of a memory  
> leak if the return value is not freed in the caller (and, indeed, it  
> is not in the mondo patch you attach).

Thank you for pointing this out! My assumption that nesting the call to
mr_stresc() inside sprintf() makes it so that the memory is freed when
the outside function, i.e. sprintf() finishes is obviously wrong as I've
also verified with valgrind now. To address this I define a variable to
store the result of mr_stresc() and explicitly free it in the attached
revised version.

> 2.  Not enough memory is allocated so you're going to overrun the  
> buffer anytime there is a character to escape.  Have a closer look at  
> the manpage for strspn().

[Note: I find remarks like 'Have a closer look...' unhelpful.]

So strspn() is not what we want, fair enough. Apparently, there is no
other standard function that is either, so I use a modified version of
the while loop in the revised version instead. I you have a constructive
suggestion what could be used instead, I'd be absolutely interested.

Please find a revised version of the demo program with the two above
changes attached. Again, comments more than welcome! (The actual mondo
patch would be changed accordingly as well of course.)

> 
> -Steve

Cheers,
Andree
-- 
Andree Leidenfrost
@ Debian Developer
Sydney - Australia

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char *mr_stresc(const char *instr, const char *toesc, const char escchr) {

  char *inptr = NULL;
  char *retstr = NULL;
  char *retptr = NULL;
  char *escptr = NULL;
  int cnt = 0;

  inptr = (char *)instr;
  
  while (*inptr != '\0') {
    escptr = (char *)toesc;
    while (*escptr != '\0') {
      if (*inptr == *escptr++) {
	cnt++;
	break;
      }
    }
    *inptr++;
  }
  inptr = (char *)instr;

  retstr = (char *)malloc(strlen(inptr) + cnt + 1);
  retptr = (char *)retstr;

  while (*inptr != '\0') {
    escptr = (char *)toesc;
    while (*escptr != '\0') {
      if (*inptr == *escptr++) {
	*retptr++ = escchr;
	break;
      }
    }
    *retptr++ = *inptr++;
  }
  *retptr = '\0';

  return retstr;

}


int main() {

  const char escchr = '\\';
  const char escape_list[3] = "`$\\";
  char string[44] = "These need escaping: `$\\, these don't: abc.";
  char *result;

  printf("Before: %s\n", string);
  result = mr_stresc(string, escape_list, escchr);
  printf("After:  %s\n", result);
  free(result);

  return 0;

}

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to