Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bc: invalid expression is allowed by parser #892

Open
mknos opened this issue Jan 1, 2025 · 1 comment
Open

bc: invalid expression is allowed by parser #892

mknos opened this issue Jan 1, 2025 · 1 comment
Labels
Priority: low get to this whenever Program: bc The bc program Status: needs help needs outside expertise or capacity Type: bug an existing feature does not work

Comments

@mknos
Copy link
Contributor

mknos commented Jan 1, 2025

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.

@briandfoy briandfoy added Type: bug an existing feature does not work Priority: low get to this whenever Program: bc The bc program Status: needs help needs outside expertise or capacity labels Jan 1, 2025
@briandfoy
Copy link
Owner

Noted. In general, I think bc probably needs to start fresh to come up with a better way of dealing with everything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: low get to this whenever Program: bc The bc program Status: needs help needs outside expertise or capacity Type: bug an existing feature does not work
Projects
None yet
Development

No branches or pull requests

2 participants