Description: notice read and write errors on input and output Quoting from the bug report: +bc (1.06-19ubuntu1) dapper; urgency=low + + * Make dc notice read and write errors on its input and output. + I grepped for mentions of the strings `putc', `print', `getc', `FILE', + `stdin', `stdout' and `stderr' and added calls to new error-checking + functions unless it was clear from the immediately-surrounding code + that the program was exiting nonzero, or would exit nonzero if the + call failed. I ignored hits in lib/getopt*, which seems to + pervasively ignore write errors when printing usage messages, in the + hope that these were correct. I _think_ I got them all. -iwj. + + -- Ian Jackson Tue, 4 Apr 2006 17:21:02 +0100 Updated by Ryan Kavanagh for 1.0.7.1 on 26 July 2017. Author: Ian Jackson Origin: other Bug-Debian: http://bugs.debian.org/488735 --- This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ --- bc/bc/execute.c +++ bc/bc/execute.c @@ -104,6 +104,7 @@ execute (void) } out_char ('\n'); } + checkferror_output(stdout); } #endif @@ -224,6 +225,7 @@ execute (void) } } fflush (stdout); + checkferror_output(stdout); break; case 'R' : /* Return from function */ @@ -259,6 +261,7 @@ execute (void) if (inst == 'W') out_char ('\n'); store_var (4); /* Special variable "last". */ fflush (stdout); + checkferror_output(stdout); pop (); break; @@ -342,6 +345,7 @@ execute (void) case 'w' : /* Write a string to the output. */ while ((ch = byte(&pc)) != '"') out_schar (ch); fflush (stdout); + checkferror_output(stdout); break; case 'x' : /* Exchange Top of Stack with the one under the tos. */ @@ -549,7 +553,10 @@ execute (void) { signal (SIGINT, use_quit); if (had_sigint) - printf ("\ninterrupted execution.\n"); + { + printf ("\ninterrupted execution.\n"); + checkferror_output(stdout); + } } } @@ -584,6 +591,7 @@ input_char (void) out_col = 0; /* Saw a new line */ } } + checkferror_input(stdin); /* Classify and preprocess the input character. */ if (isdigit(in_ch)) --- bc/bc/main.c +++ bc/bc/main.c @@ -353,6 +353,9 @@ use_quit (int sig) errno = save; #else write (1, "\n(interrupt) Exiting bc.\n", 26); +#ifdef READLINE + rl_initialize (); /* Clear readline buffer */ +#endif bc_exit(0); #endif } --- bc/bc/sbc.y +++ bc/bc/sbc.y @@ -86,7 +86,9 @@ program : /* empty */ if (interactive && !quiet) { show_bc_version (); + checkferror_output(stdout); welcome (); + checkferror_output(stdout); } } | program input_item --- bc/bc/scan.c +++ bc/bc/scan.c @@ -791,6 +791,7 @@ bcel_input (char *buf, yy_size_t *result, int max) if (bcel_len != 0) history (hist, &histev, H_ENTER, bcel_line); fflush (stdout); + checkferror_output(stdout); } if (bcel_len <= max) @@ -863,6 +864,7 @@ rl_input (char *buf, int *result, int max) add_history (rl_line); rl_line[rl_len-1] = '\n'; fflush (stdout); + checkferror_output(stdout); } if (rl_len <= max) --- bc/bc/scan.l +++ bc/bc/scan.l @@ -99,6 +99,7 @@ bcel_input (char *buf, yy_size_t *result, int max) if (bcel_len != 0) history (hist, &histev, H_ENTER, bcel_line); fflush (stdout); + checkferror_output(stdout); } if (bcel_len <= max) @@ -171,6 +172,7 @@ rl_input (char *buf, int *result, int max) add_history (rl_line); rl_line[rl_len-1] = '\n'; fflush (stdout); + checkferror_output(stdout); } if (rl_len <= max) @@ -295,6 +297,7 @@ limits return(Limits); if (c == EOF) { fprintf (stderr,"EOF encountered in a comment.\n"); + checkferror_output(stderr); break; } } --- bc/bc/util.c +++ bc/bc/util.c @@ -247,9 +247,10 @@ init_gen (void) continue_label = 0; next_label = 1; out_count = 2; - if (compile_only) + if (compile_only) { printf ("@i"); - else + checkferror_output(stdout); + } else init_load (); had_error = FALSE; did_gen = FALSE; @@ -272,6 +273,7 @@ generate (const char *str) printf ("\n"); out_count = 0; } + checkferror_output(stdout); } else load_code (str); @@ -289,6 +291,7 @@ run_code(void) if (compile_only) { printf ("@r\n"); + checkferror_output(stdout); out_count = 0; } else @@ -326,6 +329,7 @@ out_char (int ch) } putchar (ch); } + checkferror_output(stdout); } /* Output routines: Write a character CH to the standard output. @@ -355,6 +359,7 @@ out_schar (int ch) } putchar (ch); } + checkferror_output(stdout); } @@ -639,6 +644,7 @@ limits(void) #ifdef OLD_EQ_OP printf ("Old assignment operatiors are valid. (=-, =+, ...)\n"); #endif + checkferror_output(stdout); } /* bc_malloc will check the return value so all other places do not @@ -703,6 +709,7 @@ yyerror (str, va_alist) fprintf (stderr,"%s %d: ",name,line_no); vfprintf (stderr, str, args); fprintf (stderr, "\n"); + checkferror_output(stderr); had_error = TRUE; va_end (args); } @@ -743,6 +750,7 @@ ct_warn (mesg, va_alist) fprintf (stderr,"%s %d: Error: ",name,line_no); vfprintf (stderr, mesg, args); fprintf (stderr, "\n"); + checkferror_output(stderr); had_error = TRUE; } else @@ -755,6 +763,7 @@ ct_warn (mesg, va_alist) fprintf (stderr,"%s %d: (Warning) ",name,line_no); vfprintf (stderr, mesg, args); fprintf (stderr, "\n"); + checkferror_output(stderr); } va_end (args); } @@ -789,6 +798,7 @@ rt_error (mesg, va_alist) va_end (args); fprintf (stderr, "\n"); + checkferror_output(stderr); runtime_error = TRUE; } @@ -823,6 +833,7 @@ rt_warn (const char *mesg) va_end (args); fprintf (stderr, "\n"); + checkferror_output(stderr); } /* bc_exit: Make sure to reset the edit state. */ --- bc/dc/dc.c +++ bc/dc/dc.c @@ -59,6 +59,7 @@ static void bug_report_info DC_DECLVOID() { printf("Email bug reports to: bug-dc@gnu.org .\n"); + checkferror_output(stdout); } static void @@ -69,6 +70,7 @@ show_version DC_DECLVOID() This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n\ to the extent permitted by law.\n", DC_COPYRIGHT); + checkferror_output(stdout); } /* your generic usage function */ @@ -85,6 +87,7 @@ Usage: %s [OPTION] [file ...]\n\ \n\ ", progname); bug_report_info(); + checkferror_output(f); } /* returns a pointer to one past the last occurance of c in s, --- bc/dc/dc.h +++ bc/dc/dc.h @@ -76,4 +76,6 @@ typedef struct { /* This is dc's only global variable: */ extern const char *progname; /* basename of program invocation */ +#include "number.h" + #endif /* not DC_DEFS_H */ --- bc/dc/eval.c +++ bc/dc/eval.c @@ -97,12 +97,15 @@ static int input_pushback; static int input_fil DC_DECLVOID() { + int c; if (input_pushback != EOF){ - int c = input_pushback; + c = input_pushback; input_pushback = EOF; return c; } - return getc(input_fil_fp); + c = getc(input_fil_fp); + checkferror_input(input_fil_fp); + return c; } /* passed as an argument to dc_getnum */ @@ -301,11 +304,13 @@ dc_func DC_DECLARG((c, peekc, negcmp)) tmpint = dc_num2int(datum.v.number, DC_TOSS); if (2 <= tmpint && tmpint <= DC_IBASE_MAX) dc_ibase = tmpint; - else + else { fprintf(stderr, "%s: input base must be a number \ between 2 and %d (inclusive)\n", progname, DC_IBASE_MAX); + checkferror_output(stderr); + } } break; case 'k': /* set scale to value on top of stack */ @@ -313,11 +318,12 @@ between 2 and %d (inclusive)\n", tmpint = -1; if (datum.dc_type == DC_NUMBER) tmpint = dc_num2int(datum.v.number, DC_TOSS); - if ( ! (tmpint >= 0) ) + if ( ! (tmpint >= 0) ) { fprintf(stderr, "%s: scale must be a nonnegative number\n", progname); - else + checkferror_output(stderr); + } else dc_scale = tmpint; } break; @@ -341,11 +347,12 @@ between 2 and %d (inclusive)\n", tmpint = 0; if (datum.dc_type == DC_NUMBER) tmpint = dc_num2int(datum.v.number, DC_TOSS); - if ( ! (tmpint > 1) ) + if ( ! (tmpint > 1) ) { fprintf(stderr, "%s: output base must be a number greater than 1\n", progname); - else + checkferror_output(stderr); + } else dc_obase = tmpint; } break; @@ -378,6 +385,7 @@ between 2 and %d (inclusive)\n", fprintf(stderr, "%s: square root of nonnumeric attempted\n", progname); + checkferror_output(stderr); }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){ dc_free_num(&datum.v.number); datum.v.number = tmpnum; @@ -424,6 +432,7 @@ between 2 and %d (inclusive)\n", dc_garbage("at top of stack", -1); } fflush(stdout); + checkferror_output(stdout); break; case 'Q': /* quit out of top-of-stack nested evals; * pops value from stack; @@ -440,6 +449,7 @@ between 2 and %d (inclusive)\n", fprintf(stderr, "%s: Q command requires a number >= 1\n", progname); + checkferror_output(stderr); } break; case 'R': /* pop a value off of the evaluation stack,; @@ -483,11 +493,12 @@ between 2 and %d (inclusive)\n", if (datum.dc_type == DC_NUMBER) tmpint = dc_num2int(datum.v.number, DC_TOSS); if (dc_pop(&datum) == DC_SUCCESS){ - if (tmpint < 0) + if (tmpint < 0) { fprintf(stderr, "%s: array index must be a nonnegative integer\n", progname); - else + checkferror_output(stderr); + } else dc_array_set(peekc, tmpint, datum); } } @@ -499,18 +510,21 @@ between 2 and %d (inclusive)\n", tmpint = -1; if (datum.dc_type == DC_NUMBER) tmpint = dc_num2int(datum.v.number, DC_TOSS); - if (tmpint < 0) + if (tmpint < 0) { fprintf(stderr, "%s: array index must be a nonnegative integer\n", progname); - else + checkferror_output(stderr); + } else dc_push(dc_array_get(peekc, tmpint)); } return DC_EATONE; default: /* What did that user mean? */ fprintf(stderr, "%s: ", progname); + checkferror_output(stderr); dc_show_id(stdout, c, " unimplemented\n"); + checkferror_output(stdout); break; } return DC_OKAY; @@ -538,6 +552,7 @@ evalstr DC_DECLARG((string)) fprintf(stderr, "%s: eval called with non-string argument\n", progname); + checkferror_output(stderr); return DC_OKAY; } interrupt_seen = 0; @@ -635,6 +650,7 @@ evalstr DC_DECLARG((string)) return DC_FAIL; } fprintf(stderr, "%s: unexpected EOS\n", progname); + checkferror_output(stderr); return DC_OKAY; } } @@ -692,6 +708,7 @@ dc_evalfile DC_DECLARG((fp)) stdin_lookahead = EOF; for (c=getc(fp); c!=EOF; c=peekc){ peekc = getc(fp); + checkferror_input(stdin); /* * The following if() is the only place where ``stdin_lookahead'' * might be set to other than EOF: @@ -717,24 +734,30 @@ dc_evalfile DC_DECLARG((fp)) signal(SIGINT, sigint_handler); switch (dc_func(c, peekc, negcmp)){ case DC_OKAY: - if (stdin_lookahead != peekc && fp == stdin) + if (stdin_lookahead != peekc && fp == stdin) { peekc = getc(fp); + checkferror_input(stdin); + } break; case DC_EATONE: peekc = getc(fp); + checkferror_input(fp); break; case DC_EVALREG: /*commands which send us here shall guarantee that peekc!=EOF*/ c = peekc; peekc = getc(fp); + checkferror_input(fp); stdin_lookahead = peekc; if (dc_register_get(c, &datum) != DC_SUCCESS) break; dc_push(datum); /*@fallthrough@*/ case DC_EVALTOS: - if (stdin_lookahead != peekc && fp == stdin) + if (stdin_lookahead != peekc && fp == stdin) { peekc = getc(fp); + checkferror_input(stdin); + } if (dc_pop(&datum) == DC_SUCCESS){ if (datum.dc_type == DC_NUMBER){ dc_push(datum); @@ -744,6 +767,7 @@ dc_evalfile DC_DECLARG((fp)) goto reset_and_exit_quit; fprintf(stderr, "%s: Q command argument exceeded \ string execution depth\n", progname); + checkferror_output(stderr); } }else{ dc_garbage("at top of stack", -1); @@ -756,8 +780,11 @@ string execution depth\n", progname); fprintf(stderr, "%s: Q command argument exceeded string execution depth\n", progname); - if (stdin_lookahead != peekc && fp == stdin) + checkferror_output(stderr); + if (stdin_lookahead != peekc && fp == stdin) { peekc = getc(fp); + checkferror_input(stdin); + } break; case DC_INT: --- bc/dc/misc.c +++ bc/dc/misc.c @@ -89,6 +89,7 @@ dc_show_id DC_DECLARG((fp, id, suffix)) fprintf(fp, "'%c' (%#o)%s", (unsigned int) id, id, suffix); else fprintf(fp, "%#o%s", (unsigned int) id, suffix); + checkferror_output(fp); } --- bc/dc/numeric.c +++ bc/dc/numeric.c @@ -133,6 +133,7 @@ dc_div DC_DECLARG((a, b, kscale, result)) bc_init_num(CastNumPtr(result)); if (bc_divide(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){ fprintf(stderr, "%s: divide by zero\n", progname); + checkferror_output(stderr); return DC_DOMAIN_ERROR; } return DC_SUCCESS; @@ -155,6 +156,7 @@ dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder)) if (bc_divmod(CastNum(a), CastNum(b), CastNumPtr(quotient), CastNumPtr(remainder), kscale)){ fprintf(stderr, "%s: divide by zero\n", progname); + checkferror_output(stderr); return DC_DOMAIN_ERROR; } return DC_SUCCESS; @@ -173,6 +175,7 @@ dc_rem DC_DECLARG((a, b, kscale, result)) bc_init_num(CastNumPtr(result)); if (bc_modulo(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){ fprintf(stderr, "%s: remainder by zero\n", progname); + checkferror_output(stderr); return DC_DOMAIN_ERROR; } return DC_SUCCESS; @@ -225,6 +228,7 @@ dc_sqrt DC_DECLARG((value, kscale, result)) tmp = bc_copy_num(CastNum(value)); if (!bc_sqrt(&tmp, kscale)){ fprintf(stderr, "%s: square root of negative number\n", progname); + checkferror_output(stderr); bc_free_num(&tmp); return DC_DOMAIN_ERROR; } @@ -470,6 +474,7 @@ dc_dump_num DC_DECLARG((dcvalue, discard_p)) for (cur=top_of_stack; cur; cur=next) { putchar(cur->digit); + checkferror_output(stdout); next = cur->link; free(cur); } @@ -587,6 +592,8 @@ out_char (ch) out_col = 1; } putchar(ch); + checkferror_output(stdout); + checkferror_output(stderr); } } @@ -626,6 +633,7 @@ rt_error (mesg, va_alist) vfprintf (stderr, mesg, args); va_end (args); fprintf (stderr, "\n"); + checkferror_output(stderr); } @@ -659,6 +667,7 @@ rt_warn (mesg, va_alist) vfprintf (stderr, mesg, args); va_end (args); fprintf (stderr, "\n"); + checkferror_output(stderr); } --- bc/dc/stack.c +++ bc/dc/stack.c @@ -35,7 +35,10 @@ #include "dc-regdef.h" /* an oft-used error message: */ -#define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname) +#define Empty_Stack do{ \ + fprintf(stderr, "%s: stack empty\n", progname); \ + checkferror_output(stderr); \ + }while(0) /* simple linked-list implementation suffices: */ @@ -91,6 +94,7 @@ dc_binop DC_DECLARG((op, kscale)) if (dc_stack->value.dc_type!=DC_NUMBER || dc_stack->link->value.dc_type!=DC_NUMBER){ fprintf(stderr, "%s: non-numeric value\n", progname); + checkferror_output(stderr); return; } (void)dc_pop(&b); @@ -131,6 +135,7 @@ dc_binop2 DC_DECLARG((op, kscale)) if (dc_stack->value.dc_type!=DC_NUMBER || dc_stack->link->value.dc_type!=DC_NUMBER){ fprintf(stderr, "%s: non-numeric value\n", progname); + checkferror_output(stderr); return; } (void)dc_pop(&b); @@ -169,6 +174,7 @@ dc_cmpop DC_DECLVOID() if (dc_stack->value.dc_type!=DC_NUMBER || dc_stack->link->value.dc_type!=DC_NUMBER){ fprintf(stderr, "%s: non-numeric value\n", progname); + checkferror_output(stderr); return 0; } (void)dc_pop(&b); @@ -206,6 +212,7 @@ dc_triop DC_DECLARG((op, kscale)) || dc_stack->link->value.dc_type!=DC_NUMBER || dc_stack->link->link->value.dc_type!=DC_NUMBER){ fprintf(stderr, "%s: non-numeric value\n", progname); + checkferror_output(stderr); return; } (void)dc_pop(&c); @@ -327,6 +334,7 @@ dc_register_get DC_DECLARG((regid, result)) *result = dc_int2data(0); }else if (r->value.dc_type==DC_UNINITIALIZED){ fprintf(stderr, "%s: BUG: register ", progname); + checkferror_output(stderr); dc_show_id(stderr, regid, " exists but is uninitialized?\n"); return DC_FAIL; }else{ @@ -402,6 +410,7 @@ dc_register_pop DC_DECLARG((stackid, result)) r = dc_register[stackid]; if (r==NULL || r->value.dc_type==DC_UNINITIALIZED){ fprintf(stderr, "%s: stack register ", progname); + checkferror_output(stderr); dc_show_id(stderr, stackid, " is empty\n"); return DC_FAIL; } --- bc/dc/string.c +++ bc/dc/string.c @@ -94,6 +94,7 @@ dc_out_str DC_DECLARG((value, discard_flag)) dc_discard discard_flag DC_DECLEND { fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout); + checkferror_output(stdout); if (discard_flag == DC_TOSS) dc_free_str(&value); } @@ -169,6 +170,7 @@ dc_readstring DC_DECLARG((fp, ldelim, rdelim)) } *p++ = c; } + checkferror_input(fp); return dc_makestring(line_buf, (size_t)(p-line_buf)); } --- bc/h/number.h +++ bc/h/number.h @@ -23,10 +23,10 @@ You may contact the author by: e-mail: philnelson@acm.org us-mail: Philip A. Nelson - Computer Science Department, 9062 - Western Washington University - Bellingham, WA 98226-9062 - + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + *************************************************************************/ #ifndef _NUMBER_H_ @@ -140,4 +140,7 @@ void bc_out_num (bc_num num, int o_base, void (* out_char)(int), int leading_zero); void bc_out_long (long val, int size, int space, void (*out_char)(int)); + +void checkferror_input (FILE*); +void checkferror_output (FILE*); #endif --- bc/lib/number.c +++ bc/lib/number.c @@ -1713,6 +1713,7 @@ static void out_char (int c) { putchar(c); + checkferror_output(stdout); } @@ -1721,6 +1722,7 @@ pn (bc_num num) { bc_out_num (num, 10, out_char, 0); out_char ('\n'); + checkferror_output(stdout); } @@ -1732,6 +1734,28 @@ pv (char *name, unsigned char *num, int len) printf ("%s=", name); for (i=0; i