Skip to content

bc: invalid expression is allowed by parser #892

@mknos

Description

@mknos

After converting the c() function from the bc maths library to a "builtin" perl sub, I noticed the following illegal expression is accepted:

c(0.1, 0.2) + c()

The c() function requires one argument, but the functions are written to simply take the required arguments off an operand stack without much validation. I added trace statements to help debug this.

%git diff bc 
diff --git a/bin/bc b/bin/bc
index b9c2c0f..3ec5cbc 100755
--- a/bin/bc
+++ b/bin/bc
@@ -2140,7 +2140,10 @@ sub bi_c
 {
   my $stack = shift;
 
+my $n = scalar @$stack;
+warn "DBG: bi_c() called with $n arguments\n";
   my $val = pop @$stack;
+warn "DBG:  ... using argument of $val\n";
   die "c(n): missing argument\n" unless defined $val;
   my $bignum = ref $val;
   $val = $val->numify() if $bignum;
@@ -2314,9 +2317,13 @@ sub exec_stmt
           $_ eq '<<_' or $_ eq '>>_' or $_ eq '||_' or $_ eq '&&_') {
 
 # Binary operators
-         my $b = pop(@ope_stack); my $a = pop(@ope_stack);
+         my $b = pop(@ope_stack);
+         my $a = pop(@ope_stack);
 
-         if   ($_ eq '+_') { $res = $a + $b    ; 1 }
+         if   ($_ eq '+_') {
+                 warn "DBG: binop $a '+' $b\n";
+                 $res = $a + $b;
+                 }
          elsif($_ eq '-_') { $res = $a - $b    ; 1 }
          elsif($_ eq '*_') { $res = $a * $b    ; 1 }
          elsif($_ eq '/_') { die 'divide by 0' if ($bignum ? $b->is_zero : $b == 0); $res = $a / $b }
%perl bc -l
c(0.1, 0.2) + c()
DBG: bi_c() called with 2 arguments
DBG:  ... using argument of 0.2
DBG: bi_c() called with 2 arguments
DBG:  ... using argument of 0.980066577841242
DBG: binop 0.1 '+' 0.556967252809642
0.656967252809642
quit
%

So the 0.1 argument is passed to neither instance of c(); instead it is taken last as an argument to the addition operator. The result of the 1st c() is taken as the argument to the 2nd c(). The result of the 2nd c() is added to 0.1, which is equivalent to:

%bc.gavin --version
bc.gavin 5.2.1
Copyright (c) 2018-2021 Gavin D. Howard and contributors
Report bugs at: https://git.yzena.com/gavin/bc

This is free software with ABSOLUTELY NO WARRANTY.
%bc.gavin -l -e 'c(c(0.2)) + 0.1'
.65696725280964238181

To solve this, I think bc would need to be aware of the number of arguments a function is actually passed as per argument-list (a,b,c). Flattening all argument lists into a single operand stack results in loss of the argument count per function. I have no current solution at this time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority: lowget to this wheneverProgram: bcThe bc programStatus: needs helpneeds outside expertise or capacityType: bugan existing feature does not work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions