aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2003-09-14 04:06:12 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2003-09-14 04:06:12 +0000
commit8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a (patch)
tree19d33618ba3c558cd34ab743fea1a2a52f6949d0
parent7c59a83a779fa9cb92b9d37e462a130c380d14d4 (diff)
downloadbusybox-w32-8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a.tar.gz
busybox-w32-8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a.tar.bz2
busybox-w32-8aac05bfe5ffdbc4c9591d7d5b486c0af0769a7a.zip
Patch from Rob Landley
Fixed a memory leak in add_cmd/add_cmd_str by moving the allocation of sed_cmd down to where it's actually first needed. In get_address, if index_of_next_unescaped_regexp_delim ever failed, we wouldn't notice because the return value was added to idx, which was already guaranteed to be > 0. (This is buried in the changes made when I redid get_address to be based on pointer arithmetic, because all the tests were gratuitously dereferencing with a constant zero, which wasn't obvious.) Comment in parse_regex_delim was wrong: 's' and 'y' both call it. The reason "sed_cmd->num_backrefs = 0;" isn't needed is that sed_cmd was allocated with cmalloc, which zeroes memory. Different handling of space after \ in i... Different handling of pattern "s/a/b s/c/d" Cool, resursive reads don't cause a crash. :) Fixed "sed -f blah filename - < filename" since GNU sed was handling both - and filenames on the same line. (You can even list - more than once, although it's immediate EOF...)
-rw-r--r--editors/sed.c107
1 files changed, 47 insertions, 60 deletions
diff --git a/editors/sed.c b/editors/sed.c
index f297db83b..7174288a2 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -73,7 +73,6 @@ typedef struct sed_cmd_s {
73 73
74 /* inversion flag */ 74 /* inversion flag */
75 int invert; /* the '!' after the address */ 75 int invert; /* the '!' after the address */
76// int block_cmd; /* This command is part of a group that has a command address */
77 76
78 /* Runtime flag no not if the current command match's */ 77 /* Runtime flag no not if the current command match's */
79 int still_in_range; 78 int still_in_range;
@@ -193,13 +192,16 @@ static int index_of_next_unescaped_regexp_delim(const char delimiter,
193 return -1; 192 return -1;
194} 193}
195 194
195/*
196 * Returns the index of the third delimiter
197 */
196static int parse_regex_delim(const char *cmdstr, char **match, char **replace) 198static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
197{ 199{
198 const char *cmdstr_ptr = cmdstr; 200 const char *cmdstr_ptr = cmdstr;
199 char delimiter; 201 char delimiter;
200 int idx = 0; 202 int idx = 0;
201 203
202 /* verify that the 's' is followed by something. That something 204 /* verify that the 's' or 'y' is followed by something. That something
203 * (typically a 'slash') is now our regexp delimiter... */ 205 * (typically a 'slash') is now our regexp delimiter... */
204 if (*cmdstr == '\0') 206 if (*cmdstr == '\0')
205 bb_error_msg_and_die(bad_format_in_subst); 207 bb_error_msg_and_die(bad_format_in_subst);
@@ -231,38 +233,35 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
231 */ 233 */
232static int get_address(char *my_str, int *linenum, regex_t ** regex) 234static int get_address(char *my_str, int *linenum, regex_t ** regex)
233{ 235{
234 int idx = 0; 236 char *pos=my_str;
235 237
236 if (isdigit(my_str[idx])) { 238 if (isdigit(*my_str)) {
237 char *endstr; 239 *linenum = strtol(my_str, &pos, 10);
238
239 *linenum = strtol(my_str, &endstr, 10);
240 /* endstr shouldnt ever equal NULL */ 240 /* endstr shouldnt ever equal NULL */
241 idx = endstr - my_str; 241 } else if (*my_str == '$') {
242 } else if (my_str[idx] == '$') {
243 *linenum = -1; 242 *linenum = -1;
244 idx++; 243 pos++;
245 } else if (my_str[idx] == '/' || my_str[idx] == '\\') { 244 } else if (*my_str == '/' || *my_str == '\\') {
246 int idx_start = 1; 245 int next, idx_start = 1;
247 char delimiter; 246 char delimiter;
248 247
249 delimiter = '/'; 248 delimiter = '/';
250 if (my_str[idx] == '\\') { 249 if (*my_str == '\\') {
251 idx_start++; 250 idx_start++;
252 delimiter = my_str[++idx]; 251 delimiter = *(++pos);
253 } 252 }
254 idx++; 253 next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
255 idx += index_of_next_unescaped_regexp_delim(delimiter, my_str + idx); 254 if (next == -1) {
256 if (idx == -1) {
257 bb_error_msg_and_die("unterminated match expression"); 255 bb_error_msg_and_die("unterminated match expression");
258 } 256 }
259 my_str[idx] = '\0'; 257 pos += next;
258 *pos = '\0';
260 259
261 *regex = (regex_t *) xmalloc(sizeof(regex_t)); 260 *regex = (regex_t *) xmalloc(sizeof(regex_t));
262 xregcomp(*regex, my_str + idx_start, REG_NEWLINE); 261 xregcomp(*regex, my_str + idx_start, REG_NEWLINE);
263 idx++; /* so it points to the next character after the last '/' */ 262 pos++; /* so it points to the next character after the last '/' */
264 } 263 }
265 return idx; 264 return pos - my_str;
266} 265}
267 266
268static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr) 267static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr)
@@ -287,7 +286,6 @@ static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr)
287 * function to save processor time, at the expense of a little more memory 286 * function to save processor time, at the expense of a little more memory
288 * (4 bits) per sed_cmd */ 287 * (4 bits) per sed_cmd */
289 288
290 /* sed_cmd->num_backrefs = 0; *//* XXX: not needed? --apparently not */
291 for (j = 0; match[j]; j++) { 289 for (j = 0; match[j]; j++) {
292 /* GNU/POSIX sed does not save more than nine backrefs */ 290 /* GNU/POSIX sed does not save more than nine backrefs */
293 if (match[j] == '\\' && match[j + 1] == '(' 291 if (match[j] == '\\' && match[j + 1] == '('
@@ -333,17 +331,17 @@ static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr)
333 331
334static void replace_slash_n(char *string) 332static void replace_slash_n(char *string)
335{ 333{
336 int i; 334 char *dest;
337 int remaining = strlen(string);
338 335
339 for (i = 0; string[i]; i++) { 336 for (dest = string; *string; string++, dest++) {
340 if ((string[i] == '\\') && (string[i + 1] == 'n')) { 337 if ((string[0] == '\\') && (string[1] == 'n')) {
341 string[i] = '\n'; 338 *dest = '\n';
342 memmove(string + i + 1, string + i + 1, remaining - 1); 339 string++;
343 } else { 340 } else {
344 remaining--; 341 *dest = *string;
345 } 342 }
346 } 343 }
344 *dest=0;
347} 345}
348 346
349static int parse_translate_cmd(sed_cmd_t * const sed_cmd, const char *cmdstr) 347static int parse_translate_cmd(sed_cmd_t * const sed_cmd, const char *cmdstr)
@@ -431,7 +429,7 @@ static int parse_file_cmd(sed_cmd_t * sed_cmd, const char *filecmdstr)
431 * re: the file to be read, the GNU manual says the following: "Note that 429 * re: the file to be read, the GNU manual says the following: "Note that
432 * if filename cannot be read, it is treated as if it were an empty file, 430 * if filename cannot be read, it is treated as if it were an empty file,
433 * without any error indication." Thus, all of the following commands are 431 * without any error indication." Thus, all of the following commands are
434 * perfectly leagal: 432 * perfectly legal:
435 * 433 *
436 * sed -e '1r noexist' 434 * sed -e '1r noexist'
437 * sed -e '1r ;' 435 * sed -e '1r ;'
@@ -496,8 +494,10 @@ static char *parse_cmd_str(sed_cmd_t * sed_cmd, char *cmdstr)
496 return (cmdstr); 494 return (cmdstr);
497} 495}
498 496
499static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr) 497static char *add_cmd(char *cmdstr)
500{ 498{
499 sed_cmd_t *sed_cmd;
500
501 /* Skip over leading whitespace and semicolons */ 501 /* Skip over leading whitespace and semicolons */
502 cmdstr += strspn(cmdstr, semicolon_whitespace); 502 cmdstr += strspn(cmdstr, semicolon_whitespace);
503 503
@@ -522,6 +522,8 @@ static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr)
522 * part1 part2 part3 522 * part1 part2 part3
523 */ 523 */
524 524
525 sed_cmd = xcalloc(1, sizeof(sed_cmd_t));
526
525 /* first part (if present) is an address: either a '$', a number or a /regex/ */ 527 /* first part (if present) is an address: either a '$', a number or a /regex/ */
526 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); 528 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
527 529
@@ -595,10 +597,7 @@ static void add_cmd_str(char *cmdstr)
595 } 597 }
596#endif 598#endif
597 do { 599 do {
598 sed_cmd_t *sed_cmd; 600 cmdstr = add_cmd(cmdstr);
599
600 sed_cmd = xcalloc(1, sizeof(sed_cmd_t));
601 cmdstr = add_cmd(sed_cmd, cmdstr);
602 } while (cmdstr && strlen(cmdstr)); 601 } while (cmdstr && strlen(cmdstr));
603} 602}
604 603
@@ -651,18 +650,6 @@ void pipe_putc(struct pipeline *const pipeline, char c)
651 650
652#define pipeputc(c) pipe_putc(pipeline, c) 651#define pipeputc(c) pipe_putc(pipeline, c)
653 652
654#if 0
655{
656 if (pipeline[pipeline_idx] == PIPE_MAGIC) {
657 pipeline = xrealloc(pipeline, pipeline_len + PIPE_GROW);
658 memset(pipeline + pipeline_len, 0, PIPE_GROW);
659 pipeline_len += PIPE_GROW;
660 pipeline[pipeline_len - 1] = PIPE_MAGIC;
661 }
662 pipeline[pipeline_idx++] = (c);
663}
664#endif
665
666static void print_subst_w_backrefs(const char *line, const char *replace, 653static void print_subst_w_backrefs(const char *line, const char *replace,
667 regmatch_t * regmatch, struct pipeline *const pipeline, int matches) 654 regmatch_t * regmatch, struct pipeline *const pipeline, int matches)
668{ 655{
@@ -1157,31 +1144,31 @@ extern int sed_main(int argc, char **argv)
1157 if (sed_cmd_head.next == NULL) { 1144 if (sed_cmd_head.next == NULL) {
1158 if (argv[optind] == NULL) 1145 if (argv[optind] == NULL)
1159 bb_show_usage(); 1146 bb_show_usage();
1160 else { 1147 else
1161 char *str_cmd = strdup(argv[optind]); 1148 add_cmd_str(strdup(argv[optind++]));
1162
1163 add_cmd_str(str_cmd);
1164 free(str_cmd);
1165 optind++;
1166 }
1167 } 1149 }
1168 1150
1169 /* argv[(optind)..(argc-1)] should be names of file to process. If no 1151 /* argv[(optind)..(argc-1)] should be names of file to process. If no
1170 * files were specified or '-' was specified, take input from stdin. 1152 * files were specified or '-' was specified, take input from stdin.
1171 * Otherwise, we process all the files specified. */ 1153 * Otherwise, we process all the files specified. */
1172 if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) { 1154 if (argv[optind] == NULL) {
1173 process_file(stdin); 1155 process_file(stdin);
1174 } else { 1156 } else {
1175 int i; 1157 int i;
1176 FILE *file; 1158 FILE *file;
1177 1159
1178 for (i = optind; i < argc; i++) { 1160 for (i = optind; i < argc; i++) {
1179 file = bb_wfopen(argv[i], "r"); 1161 if(!strcmp(argv[i], "-")) {
1180 if (file) { 1162 process_file(stdin);
1181 process_file(file); 1163 } else {
1182 fclose(file); 1164 file = bb_wfopen(argv[i], "r");
1183 } else 1165 if (file) {
1184 status = EXIT_FAILURE; 1166 process_file(file);
1167 fclose(file);
1168 } else {
1169 status = EXIT_FAILURE;
1170 }
1171 }
1185 } 1172 }
1186 } 1173 }
1187 1174