From 05551a556bbca9e4aa5fa910e1b62ea67e6177e6 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@tarantool.org>
Date: Tue, 12 Dec 2023 13:20:03 +0300
Subject: [PATCH] sql: properly check result of decimal parsing

This patch fixes a crash that can occur when SQL parses a decimal
literal that represents a number greater than or equal to 10^38.

Closes #9469

NO_DOC=bugfix
---
 .../unreleased/gh-9469-too-big-decimal.md     |  4 +++
 src/box/errcode.h                             |  1 +
 src/box/sql/build.c                           |  6 +++-
 src/box/sql/expr.c                            |  1 +
 test/box/error.result                         |  1 +
 .../gh_9469_too_big_decimals_test.lua         | 34 +++++++++++++++++++
 6 files changed, 46 insertions(+), 1 deletion(-)
 create mode 100644 changelogs/unreleased/gh-9469-too-big-decimal.md
 create mode 100644 test/sql-luatest/gh_9469_too_big_decimals_test.lua

diff --git a/changelogs/unreleased/gh-9469-too-big-decimal.md b/changelogs/unreleased/gh-9469-too-big-decimal.md
new file mode 100644
index 0000000000..641e4bde22
--- /dev/null
+++ b/changelogs/unreleased/gh-9469-too-big-decimal.md
@@ -0,0 +1,4 @@
+## bugfix/sql
+
+* Fixed a crash when a decimal literal representing a decimal number greater
+  than or equal to 10^38 was parsed in SQL (gh-9469).
diff --git a/src/box/errcode.h b/src/box/errcode.h
index 05b268f98c..b4489691b5 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -329,6 +329,7 @@ struct errcode_record {
 	/*274 */_(ER_UNCONFIGURED,		"Please call box.cfg{} first") \
 	/*275 */_(ER_CREATE_DEFAULT_FUNC,	"Failed to create field default function '%s': %s") \
 	/*276 */_(ER_DEFAULT_FUNC_FAILED,	"Error calling field default function '%s': %s") \
+	/*277 */_(ER_INVALID_DEC,		"Invalid decimal: '%s'") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index fa3f2c2a3b..5954d83de2 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -548,7 +548,11 @@ sql_add_term_default(struct Parse *parser, struct ExprSpan *expr_span)
 		const char *str = tt_cstr(expr_span->zStart,
 					  expr_span->zEnd - expr_span->zStart);
 		decimal_t val;
-		decimal_from_string(&val, str);
+		if (decimal_from_string(&val, str) == NULL) {
+			diag_set(ClientError, ER_INVALID_DEC, str);
+			parser->is_aborted = true;
+			break;
+		}
 		size = mp_sizeof_decimal(&val);
 		buf = xregion_alloc(region, size);
 		mp_encode_decimal(buf, &val);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 4293846c43..be597430a3 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -3159,6 +3159,7 @@ expr_code_dec(struct Parse *parser, struct Expr *expr, bool is_neg, int reg)
 	return;
 error:
 	sql_xfree(value);
+	diag_set(ClientError, ER_INVALID_DEC, str);
 	parser->is_aborted = true;
 }
 
diff --git a/test/box/error.result b/test/box/error.result
index e8953d1dc4..c39f3adcc7 100644
--- a/test/box/error.result
+++ b/test/box/error.result
@@ -495,6 +495,7 @@ t;
  |   274: box.error.UNCONFIGURED
  |   275: box.error.CREATE_DEFAULT_FUNC
  |   276: box.error.DEFAULT_FUNC_FAILED
+ |   277: box.error.INVALID_DEC
  | ...
 
 test_run:cmd("setopt delimiter ''");
diff --git a/test/sql-luatest/gh_9469_too_big_decimals_test.lua b/test/sql-luatest/gh_9469_too_big_decimals_test.lua
new file mode 100644
index 0000000000..c433a7bfc0
--- /dev/null
+++ b/test/sql-luatest/gh_9469_too_big_decimals_test.lua
@@ -0,0 +1,34 @@
+local server = require('luatest.server')
+local t = require('luatest')
+
+local g = t.group()
+
+g.before_all(function()
+    g.server = server:new({alias = 'master'})
+    g.server:start()
+end)
+
+g.after_all(function()
+    g.server:stop()
+end)
+
+g.test_too_big_decimal = function()
+    g.server:exec(function()
+        local dec = '111111111111111111111111111111111111111.0'
+        local sql = ([[SELECT %s;]]):format(dec)
+        local exp = ([[Invalid decimal: '%s']]):format(dec)
+        local res, err = box.execute(sql)
+        t.assert(res == nil)
+        t.assert_equals(err.message, exp)
+
+        sql = ([[SELECT -%s;]]):format(dec)
+        res, err = box.execute(sql)
+        t.assert(res == nil)
+        t.assert_equals(err.message, exp)
+
+        sql = ([[CREATE TABLE T(i DEC PRIMARY KEY DEFAULT(%s);]]):format(dec)
+        res, err = box.execute(sql)
+        t.assert(res == nil)
+        t.assert_equals(err.message, exp)
+    end)
+end
-- 
GitLab