]> git.kaiwu.me - njs.git/commitdiff
Modules: fixed integer conversion range checks
authorDmitry Volyntsev <xeioex@nginx.com>
Sat, 23 May 2026 01:12:21 +0000 (18:12 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Tue, 26 May 2026 21:45:24 +0000 (14:45 -0700)
nginx/ngx_js.c
nginx/t/js_return.t

index f3ca74d8501b46daee392e66e21dd3fbbf4848eb..e96a209ead92ccb9e937628e385ca62490a53cf6 100644 (file)
@@ -58,6 +58,7 @@ static ngx_int_t ngx_engine_njs_string(ngx_engine_t *e,
 static void ngx_engine_njs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
     ngx_js_loc_conf_t *conf);
 static ngx_int_t ngx_js_init_preload_vm(njs_vm_t *vm, ngx_js_loc_conf_t *conf);
+static ngx_int_t ngx_js_integer_in_range(double num);
 
 static ngx_int_t ngx_njs_execute_pending_jobs(njs_vm_t *vm, ngx_log_t *log);
 static njs_int_t ngx_njs_await(njs_vm_t *vm, ngx_log_t *log,
@@ -1552,6 +1553,11 @@ ngx_qjs_integer(JSContext *cx, JSValueConst val, ngx_int_t *n)
         return NGX_ERROR;
     }
 
+    if (!ngx_js_integer_in_range(num)) {
+        (void) JS_ThrowRangeError(cx, "number is out of range");
+        return NGX_ERROR;
+    }
+
     *n = num;
 
     return NGX_OK;
@@ -2433,15 +2439,45 @@ ngx_js_log_exception(njs_vm_t *vm, ngx_log_t *log, const char *txt)
 }
 
 
+static ngx_int_t
+ngx_js_integer_in_range(double num)
+{
+    ngx_int_t  valid;
+
+#define NGX_JS_INT_T_LIMIT  ((double) NGX_MAX_INT_T_VALUE + 1.0)
+
+    /*
+     * The ngx_int_t range is half-open in double: -limit is valid, while
+     * +limit is not.  On 64-bit, NGX_MAX_INT_T_VALUE rounds to 2^63 as a
+     * double, so the expression still gives the exclusive upper bound.
+     */
+
+    valid = (num >= -NGX_JS_INT_T_LIMIT && num < NGX_JS_INT_T_LIMIT);
+
+#undef NGX_JS_INT_T_LIMIT
+
+    return valid;
+}
+
+
 ngx_int_t
 ngx_js_integer(njs_vm_t *vm, njs_value_t *value, ngx_int_t *n)
 {
+    double  num;
+
     if (!njs_value_is_valid_number(value)) {
         njs_vm_error(vm, "is not a number");
         return NGX_ERROR;
     }
 
-    *n = njs_value_number(value);
+    num = njs_value_number(value);
+
+    if (!ngx_js_integer_in_range(num)) {
+        njs_vm_range_error(vm, "number is out of range");
+        return NGX_ERROR;
+    }
+
+    *n = num;
 
     return NGX_OK;
 }
index 1ecf5a50415096f72a2edc6bf3e5e8a006c6b4d3..dd79fedce5712bb8ea79e303a1fd42c024744893 100644 (file)
@@ -55,6 +55,10 @@ http {
         location /njs {
             js_content test.njs;
         }
+
+        location /status {
+            js_content test.status;
+        }
     }
 }
 
@@ -74,11 +78,21 @@ $t->write_file('test.js', <<EOF);
         r.return(Number(r.args.c), body);
     }
 
-    export default {njs:test_njs, returnf};
+    function status(r) {
+        try {
+            r.status = Number(r.args.c);
+            r.return(200, r.status);
+
+        } catch (e) {
+            r.return(200, e.name + ': ' + e.message);
+        }
+    }
+
+    export default {njs:test_njs, returnf, status};
 
 EOF
 
-$t->try_run('no njs return')->plan(7);
+$t->try_run('no njs return')->plan(8);
 
 ###############################################################################
 
@@ -87,6 +101,8 @@ like(http_get('/?c=200&t=SEE-THIS'), qr/200 OK.*^SEE-THIS$/ms, 'return text');
 like(http_get('/?c=301&t=path'), qr/ 301 .*Location: path/s, 'return redirect');
 like(http_get('/?c=404'), qr/404 Not.*html/s, 'return error page');
 like(http_get('/?c=inv'), qr/ 500 /, 'return invalid');
+like(http_get('/status?c=1e100'), qr/RangeError: number is out of range/,
+       'status range');
 
 TODO: {
 local $TODO = 'not yet' unless has_version('0.8.6');