Blob Blame History Raw
From 30a28017ec9ffd7e26bb7867be1597250cceee23 Mon Sep 17 00:00:00 2001
From: Eike Rathke <erack@redhat.com>
Date: Thu, 16 Feb 2023 20:20:31 +0100
Subject: [PATCH] Obtain actual 0-parameter count for OR(), AND() and
 1-parameter functions

OR and AND for legacy infix notation are classified as binary
operators but in fact are functions with parameter count. In case
no argument is supplied, GetByte() returns 0 and for that case the
implicit binary operator 2 parameters were wrongly assumed.
Similar for functions expecting 1 parameter, without argument 1
was assumed. For "real" unary and binary operators the compiler
already checks parameters. Omit OR and AND and 1-parameter
functions from this implicit assumption and return the actual 0
count.

Change-Id: Ie05398c112a98021ac2875cf7b6de994aee9d882
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147173
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins

(cherry picked from commit e7ce9bddadb2db222eaa5f594ef1de2e36d57e5c)
Conflicts:
        sc/source/core/tool/interpr4.cxx

erAck: backported to 6.0.6.1
---
 formula/source/core/api/token.cxx | 13 +++++--------
 sc/source/core/tool/interpr4.cxx  | 10 +++++++++-
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 07ff7cc..0964dc4 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -106,17 +106,14 @@ sal_uInt8 FormulaToken::GetParamCount() const
         return 0;       // parameters and specials
                         // ocIf, ocIfError, ocIfNA and ocChoose not for FAP, have cByte then
 //2do: bool parameter whether FAP or not?
-    else if ( GetByte() )
+    else if (GetByte())
         return GetByte();   // all functions, also ocExternal and ocMacro
-    else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP)
-        return 2;           // binary
-    else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
-            || eOp == ocPercentSign)
-        return 1;           // unary
+    else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP && eOp != ocAnd && eOp != ocOr)
+        return 2;           // binary operators, compiler checked; OR and AND legacy but are functions
+    else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP) || eOp == ocPercentSign)
+        return 1;           // unary operators, compiler checked
     else if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
         return 0;           // no parameter
-    else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)
-        return 1;           // one parameter
     else if ( eOp == ocIf || eOp == ocIfError || eOp == ocIfNA || eOp == ocChoose )
         return 1;           // only the condition counts as parameter
     else
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 904fecd..405d8dc 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -4030,7 +4030,15 @@ StackVar ScInterpreter::Interpret()
                     nStackBase = sp - pCur->GetParamCount();
             }
             if ( nStackBase > sp )
-                nStackBase = sp;        // underflow?!?
+            {
+                SAL_WARN("sc.core", "Stack anomaly at " << aPos.Format(
+                            ScRefFlags::VALID | ScRefFlags::FORCE_DOC | ScRefFlags::TAB_3D, pDok)
+                        << "  eOp: " << static_cast<int>(eOp)
+                        << "  params: " << static_cast<int>(pCur->GetParamCount())
+                        << "  nStackBase: " << nStackBase << "  sp: " << sp);
+                nStackBase = sp;
+                assert(!"underflow");
+            }
 
             switch( eOp )
             {
-- 
2.44.0