From 4240af6a20465894dce871707271e11a05432dac Mon Sep 17 00:00:00 2001
From: itchyny <itchyny@cybozu.co.jp>
Date: Sun, 16 Feb 2025 22:08:36 +0900
Subject: [PATCH 1/2] fix: `jv_number_value` should cache the double value of
 literal numbers (#3245)

The code of `jv_number_value` is intended to cache the double value of
literal numbers, but it does not work because it accepts the `jv` struct
by value. This patch fixes the behavior by checking if the double value
is `NaN`, which indicates the unconverted value. This patch improves the
performance of major use cases; e.g. `range(1000000)` runs 25% faster.

CVE: CVE-2024-53427
Upstream-Status: Backport [https://github.com/jqlang/jq/commit/b86ff49f46a4a37e5a8e75a140cb5fd6e1331384]
Signed-off-by: Colin Pinnell McAllister <colin.mcallister@garmin.com>
---
 src/jv.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/jv.c b/src/jv.c
index 4d7bba1..9051f65 100644
--- a/src/jv.c
+++ b/src/jv.c
@@ -209,9 +209,6 @@ enum {
   JVP_NUMBER_DECIMAL = 1
 };
 
-#define JV_NUMBER_SIZE_INIT      (0)
-#define JV_NUMBER_SIZE_CONVERTED (1)
-
 #define JVP_FLAGS_NUMBER_NATIVE       JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_NATIVE, 0))
 #define JVP_FLAGS_NUMBER_NATIVE_STR   JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_NATIVE, 1))
 #define JVP_FLAGS_NUMBER_LITERAL      JVP_MAKE_FLAGS(JV_KIND_NUMBER, JVP_MAKE_PFLAGS(JVP_NUMBER_DECIMAL, 1))
@@ -619,8 +616,12 @@ static jv jvp_literal_number_new(const char * literal) {
     jv_mem_free(n);
     return JV_INVALID;
   }
+  if (decNumberIsNaN(&n->num_decimal)) {
+    jv_mem_free(n);
+    return jv_number(NAN);
+  }
 
-  jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, JV_NUMBER_SIZE_INIT, {&n->refcnt}};
+  jv r = {JVP_FLAGS_NUMBER_LITERAL, 0, 0, 0, {&n->refcnt}};
   return r;
 }
 
@@ -719,9 +720,8 @@ double jv_number_value(jv j) {
   if (JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL)) {
     jvp_literal_number* n = jvp_literal_number_ptr(j);
 
-    if (j.size != JV_NUMBER_SIZE_CONVERTED) {
+    if (isnan(n->num_double)) {
       n->num_double = jvp_literal_number_to_double(j);
-      j.size = JV_NUMBER_SIZE_CONVERTED;
     }
 
     return n->num_double;
@@ -755,6 +755,7 @@ int jvp_number_is_nan(jv n) {
   } else {
     return n.u.number != n.u.number;
   }
+  return isnan(n.u.number);
 }
 
 int jvp_number_cmp(jv a, jv b) {
-- 
2.49.0

