Skip to content

Instantly share code, notes, and snippets.

@jralls
Last active October 22, 2017 18:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jralls/acc9f8db275b6b74c5b30908aeca0119 to your computer and use it in GitHub Desktop.
Save jralls/acc9f8db275b6b74c5b30908aeca0119 to your computer and use it in GitHub Desktop.
Backtrace of GncNumeric abort
Thread 1 hit Breakpoint 1, 0x76e2b28b in msvcrt!abort ()
from C:\WINDOWS\System32\msvcrt.dll
(gdb) bt
#0 0x76e2b28b in msvcrt!abort () from C:\WINDOWS\System32\msvcrt.dll
#1 0x67f8ed0a in uw_init_context_1 ()
from C:\gcdev64\gnucash\unstable\build\gnucash-git\bin\libgnc-core-utils.dll
#2 0x67f8f50d in _Unwind_Resume ()
from C:\gcdev64\gnucash\unstable\build\gnucash-git\bin\libgnc-core-utils.dll
#3 0x00403691 in GncNumeric::GncNumeric (this=0x83fdd8, str=...,
autoround=false)
at C:/gcdev64/gnucash/unstable/src/gnucash-git/libgnucash/engine/gnc-numeric.cpp:137
#4 0x00408787 in GncNumeric::numeric_from_string (this=0x83fe38,
str=0x83fe8b "-1/0", n=0x83fe78)
at C:/gcdev64/gnucash/unstable/src/gnucash-git/libgnucash/engine/gnc-numeric.cpp:1217
#5 0x00408943 in string_to_gnc_numeric (str=0x83fe8b "-1/0", n=0x83fe78)
at C:/gcdev64/gnucash/unstable/src/gnucash-git/libgnucash/engine/gnc-numeric.cpp:1239
#6 0x00410881 in check_gnc_throw ()
at C:/gcdev64/gnucash/unstable/src/gnucash-git/libgnucash/engine/test/test-numeric.cpp:115
#7 0x004187f1 in run_test ()
at C:/gcdev64/gnucash/unstable/src/gnucash-git/libgnucash/engine/test/test-numeric.cpp:907
#8 0x00418844 in main (argc=1, argv=0x2d1e3a8)
at C:/gcdev64/gnucash/unstable/src/gnucash-git/libgnucash/engine/test/test-numeric.cpp:925
(gdb)
From 68ab5ae680d52b677696384377bfe63b13be0360 Mon Sep 17 00:00:00 2001
From: John Ralls <jralls@ceridwen.us>
Date: Sun, 22 Oct 2017 11:52:42 -0700
Subject: [PATCH] Exception experiments.
---
libgnucash/engine/gnc-numeric.cpp | 178 ++++++++++++++++++--------------
libgnucash/engine/gnc-numeric.hpp | 3 +
libgnucash/engine/test/test-numeric.cpp | 15 +++
3 files changed, 118 insertions(+), 78 deletions(-)
diff --git a/libgnucash/engine/gnc-numeric.cpp b/libgnucash/engine/gnc-numeric.cpp
index 0b7770a..e16092e 100644
--- a/libgnucash/engine/gnc-numeric.cpp
+++ b/libgnucash/engine/gnc-numeric.cpp
@@ -141,80 +141,87 @@ GncNumeric::GncNumeric(const std::string& str, bool autoround)
*/
if (str.empty())
throw std::invalid_argument("Can't construct a GncNumeric from an empty string.");
- if (regex_search(str, m, hex_rational))
- {
- GncNumeric n(stoll(m[1].str(), nullptr, 16),
- stoll(m[2].str(), nullptr, 16));
- m_num = n.num();
- m_den = n.denom();
- return;
- }
- if (regex_search(str, m, hex_over_num))
- {
- GncNumeric n(stoll(m[1].str(), nullptr, 16),
- stoll(m[2].str()));
- m_num = n.num();
- m_den = n.denom();
- return;
- }
- if (regex_search(str, m, num_over_hex))
- {
- GncNumeric n(stoll(m[1].str()),
- stoll(m[2].str(), nullptr, 16));
- m_num = n.num();
- m_den = n.denom();
- return;
- }
- if (regex_search(str, m, numeral_rational))
- {
- GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
- m_num = n.num();
- m_den = n.denom();
- return;
- }
- if (regex_search(str, m, decimal))
- {
- GncInt128 high(stoll(m[1].str()));
- GncInt128 low(stoll(m[2].str()));
- int64_t d = powten(m[2].str().length());
- GncInt128 n = high * d + (high > 0 ? low : -low);
- if (!autoround && n.isBig())
- {
- std::ostringstream errmsg;
- errmsg << "Decimal string " << m[1].str() << "." << m[2].str()
- << "can't be represented in a GncNumeric without rounding.";
- throw std::overflow_error(errmsg.str());
- }
- while (n.isBig() && d > 0)
- {
- n >>= 1;
- d >>= 1;
- }
- if (n.isBig()) //Shouldn't happen, of course
- {
- std::ostringstream errmsg;
- errmsg << "Decimal string " << m[1].str() << "." << m[2].str()
- << " can't be represented in a GncNumeric, even after reducing denom to " << d;
- throw std::overflow_error(errmsg.str());
- }
- GncNumeric gncn(static_cast<int64_t>(n), d);
- m_num = gncn.num();
- m_den = gncn.denom();
- return;
- }
- if (regex_search(str, m, hex))
- {
- GncNumeric n(stoll(m[1].str(), nullptr, 16),INT64_C(1));
- m_num = n.num();
- m_den = n.denom();
- return;
- }
- if (regex_search(str, m, numeral))
+ try
{
- GncNumeric n(stoll(m[1].str()), INT64_C(1));
- m_num = n.num();
- m_den = n.denom();
- return;
+ if (regex_search(str, m, hex_rational))
+ {
+ GncNumeric n(stoll(m[1].str(), nullptr, 16),
+ stoll(m[2].str(), nullptr, 16));
+ m_num = n.num();
+ m_den = n.denom();
+ return;
+ }
+ if (regex_search(str, m, hex_over_num))
+ {
+ GncNumeric n(stoll(m[1].str(), nullptr, 16),
+ stoll(m[2].str()));
+ m_num = n.num();
+ m_den = n.denom();
+ return;
+ }
+ if (regex_search(str, m, num_over_hex))
+ {
+ GncNumeric n(stoll(m[1].str()),
+ stoll(m[2].str(), nullptr, 16));
+ m_num = n.num();
+ m_den = n.denom();
+ return;
+ }
+ if (regex_search(str, m, numeral_rational))
+ {
+ GncNumeric n(stoll(m[1].str()), stoll(m[2].str()));
+ m_num = n.num();
+ m_den = n.denom();
+ return;
+ }
+ if (regex_search(str, m, decimal))
+ {
+ GncInt128 high(stoll(m[1].str()));
+ GncInt128 low(stoll(m[2].str()));
+ int64_t d = powten(m[2].str().length());
+ GncInt128 n = high * d + (high > 0 ? low : -low);
+ if (!autoround && n.isBig())
+ {
+ std::ostringstream errmsg;
+ errmsg << "Decimal string " << m[1].str() << "." << m[2].str()
+ << "can't be represented in a GncNumeric without rounding.";
+ throw std::overflow_error(errmsg.str());
+ }
+ while (n.isBig() && d > 0)
+ {
+ n >>= 1;
+ d >>= 1;
+ }
+ if (n.isBig()) //Shouldn't happen, of course
+ {
+ std::ostringstream errmsg;
+ errmsg << "Decimal string " << m[1].str() << "." << m[2].str()
+ << " can't be represented in a GncNumeric, even after reducing denom to " << d;
+ throw std::overflow_error(errmsg.str());
+ }
+ GncNumeric gncn(static_cast<int64_t>(n), d);
+ m_num = gncn.num();
+ m_den = gncn.denom();
+ return;
+ }
+ if (regex_search(str, m, hex))
+ {
+ GncNumeric n(stoll(m[1].str(), nullptr, 16),INT64_C(1));
+ m_num = n.num();
+ m_den = n.denom();
+ return;
+ }
+ if (regex_search(str, m, numeral))
+ {
+ GncNumeric n(stoll(m[1].str()), INT64_C(1));
+ m_num = n.num();
+ m_den = n.denom();
+ return;
+ }
+ }
+ catch (std::invalid_argument& err)
+ {
+ throw;
}
std::ostringstream errmsg;
errmsg << "String " << str << " contains no recognizable numeric value.";
@@ -1202,22 +1209,37 @@ gnc_num_dbg_to_string(gnc_numeric n)
return p;
}
-gboolean
-string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
+bool
+GncNumeric::numeric_from_string (const char* str, gnc_numeric *n) noexcept
{
try
{
GncNumeric an(str);
*n = static_cast<gnc_numeric>(an);
- return TRUE;
+ return true;
}
- catch (const std::exception& err)
+ catch (std::invalid_argument& err)
{
PWARN("%s", err.what());
- return FALSE;
+ return false;
+ }
+ catch (std::overflow_error& err)
+ {
+ PWARN("%s", err.what());
+ return false;
}
}
+gboolean
+string_to_gnc_numeric(const gchar* str, gnc_numeric *n)
+{
+ if (g_strcmp0(str, "-1/0") == 0)
+ PERR("Error Value in string!");
+ GncNumeric numeric;
+ bool result = numeric.numeric_from_string(str, n);
+ return result ? TRUE : FALSE;
+}
+
/* *******************************************************************
* GValue handling
********************************************************************/
diff --git a/libgnucash/engine/gnc-numeric.hpp b/libgnucash/engine/gnc-numeric.hpp
index d9ff3d7..49d065f 100644
--- a/libgnucash/engine/gnc-numeric.hpp
+++ b/libgnucash/engine/gnc-numeric.hpp
@@ -228,6 +228,9 @@ public:
* details.
*/
std::string to_string() const noexcept;
+ /** Fill a GncNumeric from a string
+ */
+ bool numeric_from_string (const char* str, gnc_numeric *n) noexcept;
/**
* @return true if the denominator is a power of ten, false otherwise.
*/
diff --git a/libgnucash/engine/test/test-numeric.cpp b/libgnucash/engine/test/test-numeric.cpp
index 2f284f7..7617c74 100644
--- a/libgnucash/engine/test/test-numeric.cpp
+++ b/libgnucash/engine/test/test-numeric.cpp
@@ -27,6 +27,7 @@ extern "C"
#include "config.h"
#include <ctype.h>
#include <glib.h>
+#include <glib/gprintf.h>
#include "cashobjects.h"
#include "test-stuff.h"
#include "test-engine-stuff.h"
@@ -106,6 +107,19 @@ check_binary_op_r (gnc_numeric expected,
g_free (str);
}
+static void
+check_gnc_throw (void)
+{
+ const char str[] = "-1/0";
+ gnc_numeric n;
+ if (string_to_gnc_numeric(str, &n))
+ {
+ g_printf ("Well, it didn't abort, but it also succeeded.\n");
+ return;
+ }
+ g_printf ("Creation correctly failed.\n");
+}
+
/* ======================================================= */
static gboolean
@@ -890,6 +904,7 @@ check_mult_div (void)
static void
run_test (void)
{
+ check_gnc_throw ();
check_eq_operator ();
check_reduce ();
check_equality_operator ();
--
1.9.4.msysgit.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment