Summary (Describe the bug)
On jq commit 5f2a14dd1b03a8b43015058ed006dd4ab24fb58f, the ordinary CLI
array-index surface still triggers undefined behavior when infinite is used
as an array index for has(...) or del(...).
On a sanitizer build, these witness commands both hit an inf to int
conversion error:
jq -c 'has(infinite)'
jq -c 'del(.[infinite])'
Nearby controls on the same build behave sensibly:
has(1) returns true
has(nan) returns false
del(.[1]) returns [0]
del(.[nan]) returns [0,1]
getpath([infinite]) returns null
This report is intentionally limited to the reproduced current-head UBSan
witness on jq's normal array-index surface. I am not claiming memory
corruption or exploitability beyond the observed undefined behavior.
Reproduction (To Reproduce)
One working build recipe:
git clone https://github.com/jqlang/jq.git
cd jq
git checkout 5f2a14dd1b03a8b43015058ed006dd4ab24fb58f
autoreconf -fi
CC=clang \
CFLAGS='-O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer' \
LDFLAGS='-fsanitize=address,undefined' \
./configure --with-oniguruma=builtin --disable-docs
make -j"$(nproc)"
Witness commands:
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'has(infinite)'
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'del(.[infinite])'
Useful controls:
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'has(1)'
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'has(nan)'
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'del(.[1])'
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'del(.[nan])'
echo '[0,1]' | ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 ./jq -c 'getpath([infinite])'
Observed Result / Expected Behavior
Fresh witness/control summary on commit
5f2a14dd1b03a8b43015058ed006dd4ab24fb58f:
has(1) -> exit 0, stdout: true
has(nan) -> exit 0, stdout: false
has(infinite) -> exit 1, UBSan runtime error
del(.[1]) -> exit 0, stdout: [0]
del(.[nan]) -> exit 0, stdout: [0,1]
del(.[infinite]) -> exit 1, UBSan runtime error
getpath([infinite]) -> exit 0, stdout: null
Observed behavior: has(infinite) and del(.[infinite]) trigger UBSan on
inf to int conversion.
Expected behavior: jq should reject or normalize infinite array indices without
undefined behavior, consistent with nearby special-number handling that already
fails closed or returns a stable non-crashing result.
Sanitized UBSan excerpts:
src/jv_aux.c:249:33: runtime error: inf is outside the range of representable values of type 'int'
#0 ... in jv_has src/jv_aux.c:249:33
#1 ... in jq_next src/execute.c:916:21
#2 ... in process src/main.c:179:31
#3 ... in main src/main.c:682:15
src/jv_aux.c:322:22: runtime error: inf is outside the range of representable values of type 'int'
#0 ... in jv_dels src/jv_aux.c:322:22
#1 ... in delpaths_sorted src/jv_aux.c:498:14
#2 ... in jv_delpaths src/jv_aux.c:539:10
#3 ... in jq_next src/execute.c:916:21
Environment
- Source revision / version:
jq-1.8.2rc1 at commit
5f2a14dd1b03a8b43015058ed006dd4ab24fb58f
- Host OS: Arch Linux
- Architecture:
x86_64
- Toolchain:
clang 22.1.3
- Build mode: AddressSanitizer + UndefinedBehaviorSanitizer with
-O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer
- Configure flags:
--with-oniguruma=builtin --disable-docs
- Runtime knobs:
ASAN_OPTIONS=detect_leaks=0 and
UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
Additional Context
The failing surface is ordinary jq CLI behavior, not a harness-only helper.
The sibling controls show that jq already distinguishes special numeric array
indices in nearby paths:
has(nan) already fails closed
del(.[nan]) already fails closed
getpath([infinite]) already stays clean on the same input family
The retained witness is consistent with jv_has() and jv_dels() still doing
raw double -> int conversions for infinite indices while nearby logic already
normalizes or bounds the value first.
Affected Commit
- latest reproduced head:
5f2a14dd1b03a8b43015058ed006dd4ab24fb58f
Proposed Patch Or Fix Sketch
I am not attaching a full patch yet because jq's current callers do not all
want the same fallback behavior:
has(nan) returns false
del(.[nan]) leaves the input unchanged
getpath([infinite]) returns null
The narrow fix direction seems to be:
- add one shared numeric-array-index normalization helper before any
double -> int cast
- reject
nan, +infinity, and -infinity before the cast
- handle out-of-range finite values in the same helper
- let each caller map the normalized result into its existing caller-specific
behavior
At minimum, regression coverage should include:
has(1)
has(nan)
has(infinite)
del(.[1])
del(.[nan])
del(.[infinite])
getpath([infinite])
Summary (Describe the bug)
On jq commit
5f2a14dd1b03a8b43015058ed006dd4ab24fb58f, the ordinary CLIarray-index surface still triggers undefined behavior when
infiniteis usedas an array index for
has(...)ordel(...).On a sanitizer build, these witness commands both hit an
inftointconversion error:
jq -c 'has(infinite)'jq -c 'del(.[infinite])'Nearby controls on the same build behave sensibly:
has(1)returnstruehas(nan)returnsfalsedel(.[1])returns[0]del(.[nan])returns[0,1]getpath([infinite])returnsnullThis report is intentionally limited to the reproduced current-head UBSan
witness on jq's normal array-index surface. I am not claiming memory
corruption or exploitability beyond the observed undefined behavior.
Reproduction (To Reproduce)
One working build recipe:
Witness commands:
Useful controls:
Observed Result / Expected Behavior
Fresh witness/control summary on commit
5f2a14dd1b03a8b43015058ed006dd4ab24fb58f:Observed behavior:
has(infinite)anddel(.[infinite])trigger UBSan oninftointconversion.Expected behavior: jq should reject or normalize infinite array indices without
undefined behavior, consistent with nearby special-number handling that already
fails closed or returns a stable non-crashing result.
Sanitized UBSan excerpts:
Environment
jq-1.8.2rc1at commit5f2a14dd1b03a8b43015058ed006dd4ab24fb58fx86_64clang 22.1.3-O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer--with-oniguruma=builtin --disable-docsASAN_OPTIONS=detect_leaks=0andUBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1Additional Context
The failing surface is ordinary jq CLI behavior, not a harness-only helper.
The sibling controls show that jq already distinguishes special numeric array
indices in nearby paths:
has(nan)already fails closeddel(.[nan])already fails closedgetpath([infinite])already stays clean on the same input familyThe retained witness is consistent with
jv_has()andjv_dels()still doingraw
double -> intconversions for infinite indices while nearby logic alreadynormalizes or bounds the value first.
Affected Commit
5f2a14dd1b03a8b43015058ed006dd4ab24fb58fProposed Patch Or Fix Sketch
I am not attaching a full patch yet because jq's current callers do not all
want the same fallback behavior:
has(nan)returnsfalsedel(.[nan])leaves the input unchangedgetpath([infinite])returnsnullThe narrow fix direction seems to be:
double -> intcastnan,+infinity, and-infinitybefore the castbehavior
At minimum, regression coverage should include:
has(1)has(nan)has(infinite)del(.[1])del(.[nan])del(.[infinite])getpath([infinite])