Compare commits

...

3 Commits
c8s ... c10

Author SHA1 Message Date
753826117d import UBI jq-1.7.1-11.el10 2025-11-11 22:00:12 +00:00
eb87df2276 import UBI jq-1.7.1-8.el10_0.1 2025-08-05 06:43:43 +00:00
349fdd5996 import UBI jq-1.7.1-8.el10 2025-05-14 19:04:47 +00:00
24 changed files with 475 additions and 33656 deletions

View File

@ -1 +0,0 @@
1

3
.gitignore vendored
View File

@ -1,2 +1 @@
SOURCES/jq-1.6.tar.gz
/jq-1.6.tar.gz
jq-1.7.1.tar.gz

File diff suppressed because it is too large Load Diff

206
0001-CVE-2024-23337.patch Normal file
View File

@ -0,0 +1,206 @@
Based on:
commit de21386681c0df0104a99d9d09db23a9b2a78b1e
Author: itchyny <itchyny@cybozu.co.jp>
Date: Wed May 21 07:45:00 2025 +0900
Fix signed integer overflow in jvp_array_write and jvp_object_rehash
This commit fixes signed integer overflow and SEGV issues on growing
arrays and objects. The size of arrays and objects is now limited to
`536870912` (`0x20000000`). This fixes CVE-2024-23337 and fixes #3262.
diff -up jq-jq-1.7.1/src/jv_aux.c.orig jq-jq-1.7.1/src/jv_aux.c
--- jq-jq-1.7.1/src/jv_aux.c.orig 2023-12-13 20:20:22.000000000 +0100
+++ jq-jq-1.7.1/src/jv_aux.c 2025-06-25 10:10:45.542441628 +0200
@@ -193,18 +193,19 @@ jv jv_set(jv t, jv k, jv v) {
if (slice_len < insert_len) {
// array is growing
int shift = insert_len - slice_len;
- for (int i = array_len - 1; i >= end; i--) {
+ for (int i = array_len - 1; i >= end && jv_is_valid(t); i--) {
t = jv_array_set(t, i + shift, jv_array_get(jv_copy(t), i));
}
} else if (slice_len > insert_len) {
// array is shrinking
int shift = slice_len - insert_len;
- for (int i = end; i < array_len; i++) {
+ for (int i = end; i < array_len && jv_is_valid(t); i++) {
t = jv_array_set(t, i - shift, jv_array_get(jv_copy(t), i));
}
- t = jv_array_slice(t, 0, array_len - shift);
+ if (jv_is_valid(t))
+ t = jv_array_slice(t, 0, array_len - shift);
}
- for (int i=0; i < insert_len; i++) {
+ for (int i = 0; i < insert_len && jv_is_valid(t); i++) {
t = jv_array_set(t, start + i, jv_array_get(jv_copy(v), i));
}
jv_free(v);
diff -up jq-jq-1.7.1/src/jv.c.orig jq-jq-1.7.1/src/jv.c
--- jq-jq-1.7.1/src/jv.c.orig 2025-06-25 10:07:24.630147714 +0200
+++ jq-jq-1.7.1/src/jv.c 2025-06-25 10:12:28.591914084 +0200
@@ -1001,6 +1001,11 @@ jv jv_array_set(jv j, int idx, jv val) {
jv_free(val);
return jv_invalid_with_msg(jv_string("Out of bounds negative array index"));
}
+ if (idx > (INT_MAX >> 2) - jvp_array_offset(j)) {
+ jv_free(j);
+ jv_free(val);
+ return jv_invalid_with_msg(jv_string("Array index too large"));
+ }
// copy/free of val,j coalesced
jv* slot = jvp_array_write(&j, idx);
jv_free(*slot);
@@ -1020,6 +1025,7 @@ jv jv_array_concat(jv a, jv b) {
// FIXME: could be faster
jv_array_foreach(b, i, elem) {
a = jv_array_append(a, elem);
+ if (!jv_is_valid(a)) break;
}
jv_free(b);
return a;
@@ -1292,6 +1298,7 @@ jv jv_string_indexes(jv j, jv k) {
p = jstr;
while ((p = _jq_memmem(p, (jstr + jlen) - p, idxstr, idxlen)) != NULL) {
a = jv_array_append(a, jv_number(p - jstr));
+ if (!jv_is_valid(a)) break;
p++;
}
}
@@ -1314,14 +1321,17 @@ jv jv_string_split(jv j, jv sep) {
if (seplen == 0) {
int c;
- while ((jstr = jvp_utf8_next(jstr, jend, &c)))
+ while ((jstr = jvp_utf8_next(jstr, jend, &c))) {
a = jv_array_append(a, jv_string_append_codepoint(jv_string(""), c));
+ if (!jv_is_valid(a)) break;
+ }
} else {
for (p = jstr; p < jend; p = s + seplen) {
s = _jq_memmem(p, jend - p, sepstr, seplen);
if (s == NULL)
s = jend;
a = jv_array_append(a, jv_string_sized(p, s - p));
+ if (!jv_is_valid(a)) break;
// Add an empty string to denote that j ends on a sep
if (s + seplen == jend && seplen != 0)
a = jv_array_append(a, jv_string(""));
@@ -1339,8 +1349,10 @@ jv jv_string_explode(jv j) {
const char* end = i + len;
jv a = jv_array_sized(len);
int c;
- while ((i = jvp_utf8_next(i, end, &c)))
+ while ((i = jvp_utf8_next(i, end, &c))) {
a = jv_array_append(a, jv_number(c));
+ if (!jv_is_valid(a)) break;
+ }
jv_free(j);
return a;
}
@@ -1614,10 +1626,13 @@ static void jvp_object_free(jv o) {
}
}
-static jv jvp_object_rehash(jv object) {
+static int jvp_object_rehash(jv *objectp) {
+ jv object = *objectp;
assert(JVP_HAS_KIND(object, JV_KIND_OBJECT));
assert(jvp_refcnt_unshared(object.u.ptr));
int size = jvp_object_size(object);
+ if (size > INT_MAX >> 2)
+ return 0;
jv new_object = jvp_object_new(size * 2);
for (int i=0; i<size; i++) {
struct object_slot* slot = jvp_object_get_slot(object, i);
@@ -1630,7 +1645,8 @@ static jv jvp_object_rehash(jv object) {
}
// references are transported, just drop the old table
jv_mem_free(jvp_object_ptr(object));
- return new_object;
+ *objectp = new_object;
+ return 1;
}
static jv jvp_object_unshare(jv object) {
@@ -1659,27 +1675,32 @@ static jv jvp_object_unshare(jv object)
return new_object;
}
-static jv* jvp_object_write(jv* object, jv key) {
+static int jvp_object_write(jv* object, jv key, jv **valpp) {
*object = jvp_object_unshare(*object);
int* bucket = jvp_object_find_bucket(*object, key);
struct object_slot* slot = jvp_object_find_slot(*object, key, bucket);
if (slot) {
// already has the key
jvp_string_free(key);
- return &slot->value;
+ *valpp = &slot->value;
+ return 1;
}
slot = jvp_object_add_slot(*object, key, bucket);
if (slot) {
slot->value = jv_invalid();
} else {
- *object = jvp_object_rehash(*object);
+ if (!jvp_object_rehash(object)) {
+ *valpp = NULL;
+ return 0;
+ }
bucket = jvp_object_find_bucket(*object, key);
assert(!jvp_object_find_slot(*object, key, bucket));
slot = jvp_object_add_slot(*object, key, bucket);
assert(slot);
slot->value = jv_invalid();
}
- return &slot->value;
+ *valpp = &slot->value;
+ return 1;
}
static int jvp_object_delete(jv* object, jv key) {
@@ -1779,7 +1800,11 @@ jv jv_object_set(jv object, jv key, jv v
assert(JVP_HAS_KIND(object, JV_KIND_OBJECT));
assert(JVP_HAS_KIND(key, JV_KIND_STRING));
// copy/free of object, key, value coalesced
- jv* slot = jvp_object_write(&object, key);
+ jv* slot;
+ if (!jvp_object_write(&object, key, &slot)) {
+ jv_free(object);
+ return jv_invalid_with_msg(jv_string("Object too big"));
+ }
jv_free(*slot);
*slot = value;
return object;
@@ -1804,6 +1829,7 @@ jv jv_object_merge(jv a, jv b) {
assert(JVP_HAS_KIND(a, JV_KIND_OBJECT));
jv_object_foreach(b, k, v) {
a = jv_object_set(a, k, v);
+ if (!jv_is_valid(a)) break;
}
jv_free(b);
return a;
@@ -1823,6 +1849,7 @@ jv jv_object_merge_recursive(jv a, jv b)
jv_free(elem);
a = jv_object_set(a, k, v);
}
+ if (!jv_is_valid(a)) break;
}
jv_free(b);
return a;
diff -up jq-jq-1.7.1/tests/jq.test.orig jq-jq-1.7.1/tests/jq.test
--- jq-jq-1.7.1/tests/jq.test.orig 2025-06-25 10:07:24.630712938 +0200
+++ jq-jq-1.7.1/tests/jq.test 2025-06-25 10:10:45.542877328 +0200
@@ -198,6 +198,10 @@ null
[0,1,2]
[0,5,2]
+try (.[999999999] = 0) catch .
+null
+"Array index too large"
+
#
# Multiple outputs, iteration
#

View File

@ -1,25 +0,0 @@
diff -up jq-1.6/src/jv.c.iteration jq-1.6/src/jv.c
--- jq-1.6/src/jv.c.iteration 2022-10-21 14:17:26.977551386 +0200
+++ jq-1.6/src/jv.c 2022-10-21 14:18:43.562430867 +0200
@@ -308,6 +308,7 @@ static jv jvp_literal_number_new(const c
n->refcnt = JV_REFCNT_INIT;
n->literal_data = NULL;
decContext *ctx = DEC_CONTEXT();
+ decContextClearStatus(ctx, DEC_Conversion_syntax);
decNumberFromString(&n->num_decimal, literal, ctx);
n->num_double = NAN;
diff -up jq-1.6/tests/optional.test.iteration jq-1.6/tests/optional.test
--- jq-1.6/tests/optional.test.iteration 2022-10-21 14:22:04.191734821 +0200
+++ jq-1.6/tests/optional.test 2022-10-21 14:23:45.820901911 +0200
@@ -17,4 +17,9 @@ strftime("%A, %B %e, %Y")
1435677542.822351
"Tuesday, June 30, 2015"
-
+# iteration must continue after hello
+.[]|tonumber?
+["1", "hello", "3", 4]
+1
+3
+4

141
0002-CVE-2025-48060.patch Normal file
View File

@ -0,0 +1,141 @@
CVE-2025-48060 fix based on:
commit dc849e9bb74a7a164a3ea52f661cc712b1ffbd43
Author: itchyny <itchyny@cybozu.co.jp>
Date: Tue Mar 4 22:13:55 2025 +0900
Improve performance of repeating strings (#3272)
This commit improves the performance of repeating strings, by copying
the result string instead of the string being repeated. Also it adds
an error message when the result string is too long.
and
commit c6e041699d8cd31b97375a2596217aff2cfca85b
Author: itchyny <itchyny@cybozu.co.jp>
Date: Sat May 31 11:46:40 2025 +0900
Fix heap buffer overflow when formatting an empty string
The `jv_string_empty` did not properly null-terminate the string data,
which could lead to a heap buffer overflow. The test case of
GHSA-p7rr-28xf-3m5w (`0[""*0]`) was fixed by the commit dc849e9bb74a,
but another case (`0[[]|implode]`) was still vulnerable. This commit
ensures string data is properly null-terminated, and fixes CVE-2025-48060.
diff -up jq-jq-1.7.1/src/builtin.c.orig jq-jq-1.7.1/src/builtin.c
--- jq-jq-1.7.1/src/builtin.c.orig 2023-12-13 20:20:22.000000000 +0100
+++ jq-jq-1.7.1/src/builtin.c 2025-06-25 10:44:54.924284670 +0200
@@ -369,21 +369,10 @@ jv binop_multiply(jv a, jv b) {
str = b;
num = a;
}
- jv res;
double d = jv_number_value(num);
- if (d < 0 || isnan(d)) {
- res = jv_null();
- } else {
- int n = d;
- size_t alen = jv_string_length_bytes(jv_copy(str));
- res = jv_string_empty(alen * n);
- for (; n > 0; n--) {
- res = jv_string_append_buf(res, jv_string_value(str), alen);
- }
- }
- jv_free(str);
jv_free(num);
- return res;
+ return jv_string_repeat(str,
+ d < 0 || isnan(d) ? -1 : d > INT_MAX ? INT_MAX : (int)d);
} else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) {
return jv_object_merge_recursive(a, b);
} else {
diff -up jq-jq-1.7.1/src/jv.c.orig jq-jq-1.7.1/src/jv.c
--- jq-jq-1.7.1/src/jv.c.orig 2025-06-25 10:53:50.314332900 +0200
+++ jq-jq-1.7.1/src/jv.c 2025-06-25 10:51:23.208740329 +0200
@@ -1125,6 +1125,7 @@ static jv jvp_string_empty_new(uint32_t
jvp_string* s = jvp_string_alloc(length);
s->length_hashed = 0;
memset(s->data, 0, length);
+ s->data[length] = 0;
jv r = {JVP_FLAGS_STRING, 0, 0, 0, {&s->refcnt}};
return r;
}
@@ -1307,6 +1308,32 @@ jv jv_string_indexes(jv j, jv k) {
return a;
}
+jv jv_string_repeat(jv j, int n) {
+ assert(JVP_HAS_KIND(j, JV_KIND_STRING));
+ if (n < 0) {
+ jv_free(j);
+ return jv_null();
+ }
+ int len = jv_string_length_bytes(jv_copy(j));
+ int64_t res_len = (int64_t)len * n;
+ if (res_len >= INT_MAX) {
+ jv_free(j);
+ return jv_invalid_with_msg(jv_string("Repeat string result too long"));
+ }
+ if (res_len == 0) {
+ jv_free(j);
+ return jv_string("");
+ }
+ jv res = jv_string_empty(res_len);
+ res = jvp_string_append(res, jv_string_value(j), len);
+ for (int curr = len, grow; curr < res_len; curr += grow) {
+ grow = MIN(res_len - curr, curr);
+ res = jvp_string_append(res, jv_string_value(res), grow);
+ }
+ jv_free(j);
+ return res;
+}
+
jv jv_string_split(jv j, jv sep) {
assert(JVP_HAS_KIND(j, JV_KIND_STRING));
assert(JVP_HAS_KIND(sep, JV_KIND_STRING));
diff -up jq-jq-1.7.1/src/jv.h.orig jq-jq-1.7.1/src/jv.h
--- jq-jq-1.7.1/src/jv.h.orig 2023-12-13 20:20:22.000000000 +0100
+++ jq-jq-1.7.1/src/jv.h 2025-06-25 10:44:54.925242109 +0200
@@ -131,6 +131,7 @@ jv jv_string_fmt(const char*, ...) JV_PR
jv jv_string_append_codepoint(jv a, uint32_t c);
jv jv_string_append_buf(jv a, const char* buf, int len);
jv jv_string_append_str(jv a, const char* str);
+jv jv_string_repeat(jv j, int n);
jv jv_string_split(jv j, jv sep);
jv jv_string_explode(jv j);
jv jv_string_implode(jv j);
diff -up jq-jq-1.7.1/tests/jq.test.orig jq-jq-1.7.1/tests/jq.test
--- jq-jq-1.7.1/tests/jq.test.orig 2025-06-25 10:53:02.390073835 +0200
+++ jq-jq-1.7.1/tests/jq.test 2025-06-25 10:51:23.209350316 +0200
@@ -1369,6 +1369,18 @@ indices(", ")
"abc"
[null,null]
+. * 100000 | [.[:10],.[-10:]]
+"abc"
+["abcabcabca","cabcabcabc"]
+
+. * 1000000000
+""
+""
+
+try (. * 1000000000) catch .
+"abc"
+"Repeat string result too long"
+
[.[] / ","]
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]
@@ -2030,6 +2042,10 @@ map(try implode catch .)
[123,["a"],[nan]]
["implode input must be an array","string (\"a\") can't be imploded, unicode codepoint needs to be numeric","number (null) can't be imploded, unicode codepoint needs to be numeric"]
+try 0[implode] catch .
+[]
+"Cannot index number with string \"\""
+
# walk
walk(.)
{"x":0}

View File

@ -1,851 +0,0 @@
man.test from commit 50a7022ea68fb37faefdcd7a35661df72fbfd655
diff --git a/tests/man.test b/tests/man.test
new file mode 100644
index 0000000..2a49eff
--- /dev/null
+++ b/tests/man.test
@@ -0,0 +1,843 @@
+.
+"Hello, world!"
+"Hello, world!"
+
+.foo
+{"foo": 42, "bar": "less interesting data"}
+42
+
+.foo
+{"notfoo": true, "alsonotfoo": false}
+null
+
+.["foo"]
+{"foo": 42}
+42
+
+.foo?
+{"foo": 42, "bar": "less interesting data"}
+42
+
+.foo?
+{"notfoo": true, "alsonotfoo": false}
+null
+
+.["foo"]?
+{"foo": 42}
+42
+
+[.foo?]
+[1,2]
+[]
+
+.[0]
+[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
+{"name":"JSON", "good":true}
+
+.[2]
+[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
+null
+
+.[-2]
+[1,2,3]
+2
+
+.[2:4]
+["a","b","c","d","e"]
+["c", "d"]
+
+.[2:4]
+"abcdefghi"
+"cd"
+
+.[:3]
+["a","b","c","d","e"]
+["a", "b", "c"]
+
+.[-2:]
+["a","b","c","d","e"]
+["d", "e"]
+
+.[]
+[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
+{"name":"JSON", "good":true}
+{"name":"XML", "good":false}
+
+.[]
+[]
+
+.[]
+{"a": 1, "b": 1}
+1
+1
+
+.foo, .bar
+{"foo": 42, "bar": "something else", "baz": true}
+42
+"something else"
+
+.user, .projects[]
+{"user":"stedolan", "projects": ["jq", "wikiflow"]}
+"stedolan"
+"jq"
+"wikiflow"
+
+.[4,2]
+["a","b","c","d","e"]
+"e"
+"c"
+
+.[] | .name
+[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]
+"JSON"
+"XML"
+
+(. + 2) * 5
+1
+15
+
+[.user, .projects[]]
+{"user":"stedolan", "projects": ["jq", "wikiflow"]}
+["stedolan", "jq", "wikiflow"]
+
+[ .[] | . * 2]
+[1, 2, 3]
+[2, 4, 6]
+
+{user, title: .titles[]}
+{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
+{"user":"stedolan", "title": "JQ Primer"}
+{"user":"stedolan", "title": "More JQ"}
+
+{(.user): .titles}
+{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
+{"stedolan": ["JQ Primer", "More JQ"]}
+
+..|.a?
+[[{"a":1}]]
+1
+
+.a + 1
+{"a": 7}
+8
+
+.a + .b
+{"a": [1,2], "b": [3,4]}
+[1,2,3,4]
+
+.a + null
+{"a": 1}
+1
+
+.a + 1
+{}
+1
+
+{a: 1} + {b: 2} + {c: 3} + {a: 42}
+null
+{"a": 42, "b": 2, "c": 3}
+
+4 - .a
+{"a":3}
+1
+
+. - ["xml", "yaml"]
+["xml", "yaml", "json"]
+["json"]
+
+10 / . * 3
+5
+6
+
+. / ", "
+"a, b,c,d, e"
+["a","b,c,d","e"]
+
+{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}
+null
+{"k": {"a": 0, "b": 2, "c": 3}}
+
+.[] | (1 / .)?
+[1,0,-1]
+1
+-1
+
+.[] | length
+[[1,2], "string", {"a":2}, null]
+2
+6
+1
+0
+
+utf8bytelength
+"\u03bc"
+2
+
+keys
+{"abc": 1, "abcd": 2, "Foo": 3}
+["Foo", "abc", "abcd"]
+
+keys
+[42,3,35]
+[0,1,2]
+
+map(has("foo"))
+[{"foo": 42}, {}]
+[true, false]
+
+map(has(2))
+[[0,1], ["a","b","c"]]
+[false, true]
+
+.[] | in({"foo": 42})
+["foo", "bar"]
+true
+false
+
+map(in([0,1]))
+[2, 0]
+[false, true]
+
+map(.+1)
+[1,2,3]
+[2,3,4]
+
+map_values(.+1)
+{"a": 1, "b": 2, "c": 3}
+{"a": 2, "b": 3, "c": 4}
+
+path(.a[0].b)
+null
+["a",0,"b"]
+
+[path(..)]
+{"a":[{"b":1}]}
+[[],["a"],["a",0],["a",0,"b"]]
+
+del(.foo)
+{"foo": 42, "bar": 9001, "baz": 42}
+{"bar": 9001, "baz": 42}
+
+del(.[1, 2])
+["foo", "bar", "baz"]
+["foo"]
+
+getpath(["a","b"])
+null
+null
+
+[getpath(["a","b"], ["a","c"])]
+{"a":{"b":0, "c":1}}
+[0, 1]
+
+setpath(["a","b"]; 1)
+null
+{"a": {"b": 1}}
+
+setpath(["a","b"]; 1)
+{"a":{"b":0}}
+{"a": {"b": 1}}
+
+setpath([0,"a"]; 1)
+null
+[{"a":1}]
+
+delpaths([["a","b"]])
+{"a":{"b":1},"x":{"y":2}}
+{"a":{},"x":{"y":2}}
+
+to_entries
+{"a": 1, "b": 2}
+[{"key":"a", "value":1}, {"key":"b", "value":2}]
+
+from_entries
+[{"key":"a", "value":1}, {"key":"b", "value":2}]
+{"a": 1, "b": 2}
+
+with_entries(.key |= "KEY_" + .)
+{"a": 1, "b": 2}
+{"KEY_a": 1, "KEY_b": 2}
+
+map(select(. >= 2))
+[1,5,3,0,7]
+[5,3,7]
+
+.[] | select(.id == "second")
+[{"id": "first", "val": 1}, {"id": "second", "val": 2}]
+{"id": "second", "val": 2}
+
+.[]|numbers
+[[],{},1,"foo",null,true,false]
+1
+
+1, empty, 2
+null
+1
+2
+
+[1,2,empty,3]
+null
+[1,2,3]
+
+try error("\($__loc__)") catch .
+null
+"{\"file\":\"<top-level>\",\"line\":1}"
+
+[paths]
+[1,[[],{"a":2}]]
+[[0],[1],[1,0],[1,1],[1,1,"a"]]
+
+[paths(scalars)]
+[1,[[],{"a":2}]]
+[[0],[1,1,"a"]]
+
+add
+["a","b","c"]
+"abc"
+
+add
+[1, 2, 3]
+6
+
+add
+[]
+null
+
+any
+[true, false]
+true
+
+any
+[false, false]
+false
+
+any
+[]
+false
+
+all
+[true, false]
+false
+
+all
+[true, true]
+true
+
+all
+[]
+true
+
+flatten
+[1, [2], [[3]]]
+[1, 2, 3]
+
+flatten(1)
+[1, [2], [[3]]]
+[1, 2, [3]]
+
+flatten
+[[]]
+[]
+
+flatten
+[{"foo": "bar"}, [{"foo": "baz"}]]
+[{"foo": "bar"}, {"foo": "baz"}]
+
+range(2;4)
+null
+2
+3
+
+[range(2;4)]
+null
+[2,3]
+
+[range(4)]
+null
+[0,1,2,3]
+
+[range(0;10;3)]
+null
+[0,3,6,9]
+
+[range(0;10;-1)]
+null
+[]
+
+[range(0;-5;-1)]
+null
+[0,-1,-2,-3,-4]
+
+floor
+3.14159
+3
+
+sqrt
+9
+3
+
+.[] | tonumber
+[1, "1"]
+1
+1
+
+.[] | tostring
+[1, "1", [1]]
+"1"
+"1"
+"[1]"
+
+map(type)
+[0, false, [], {}, null, "hello"]
+["number", "boolean", "array", "object", "null", "string"]
+
+.[] | (infinite * .) < 0
+[-1, 1]
+true
+false
+
+infinite, nan | type
+null
+"number"
+"number"
+
+sort
+[8,3,null,6]
+[null,3,6,8]
+
+sort_by(.foo)
+[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]
+[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]
+
+group_by(.foo)
+[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]
+[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]
+
+min
+[5,4,2,7]
+2
+
+max_by(.foo)
+[{"foo":1, "bar":14}, {"foo":2, "bar":3}]
+{"foo":2, "bar":3}
+
+unique
+[1,2,5,3,5,3,1,3]
+[1,2,3,5]
+
+unique_by(.foo)
+[{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}]
+[{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]
+
+unique_by(length)
+["chunky", "bacon", "kitten", "cicada", "asparagus"]
+["bacon", "chunky", "asparagus"]
+
+reverse
+[1,2,3,4]
+[4,3,2,1]
+
+contains("bar")
+"foobar"
+true
+
+contains(["baz", "bar"])
+["foobar", "foobaz", "blarp"]
+true
+
+contains(["bazzzzz", "bar"])
+["foobar", "foobaz", "blarp"]
+false
+
+contains({foo: 12, bar: [{barp: 12}]})
+{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}
+true
+
+contains({foo: 12, bar: [{barp: 15}]})
+{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}
+false
+
+indices(", ")
+"a,b, cd, efg, hijk"
+[3,7,12]
+
+indices(1)
+[0,1,2,1,3,1,4]
+[1,3,5]
+
+indices([1,2])
+[0,1,2,3,1,4,2,5,1,2,6,7]
+[1,8]
+
+index(", ")
+"a,b, cd, efg, hijk"
+3
+
+rindex(", ")
+"a,b, cd, efg, hijk"
+12
+
+inside("foobar")
+"bar"
+true
+
+inside(["foobar", "foobaz", "blarp"])
+["baz", "bar"]
+true
+
+inside(["foobar", "foobaz", "blarp"])
+["bazzzzz", "bar"]
+false
+
+inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})
+{"foo": 12, "bar": [{"barp": 12}]}
+true
+
+inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})
+{"foo": 12, "bar": [{"barp": 15}]}
+false
+
+[.[]|startswith("foo")]
+["fo", "foo", "barfoo", "foobar", "barfoob"]
+[false, true, false, true, false]
+
+[.[]|endswith("foo")]
+["foobar", "barfoo"]
+[false, true]
+
+combinations
+[[1,2], [3, 4]]
+[1, 3]
+[1, 4]
+[2, 3]
+[2, 4]
+
+combinations(2)
+[0, 1]
+[0, 0]
+[0, 1]
+[1, 0]
+[1, 1]
+
+[.[]|ltrimstr("foo")]
+["fo", "foo", "barfoo", "foobar", "afoo"]
+["fo","","barfoo","bar","afoo"]
+
+[.[]|rtrimstr("foo")]
+["fo", "foo", "barfoo", "foobar", "foob"]
+["fo","","bar","foobar","foob"]
+
+explode
+"foobar"
+[102,111,111,98,97,114]
+
+implode
+[65, 66, 67]
+"ABC"
+
+split(", ")
+"a, b,c,d, e, "
+["a","b,c,d","e",""]
+
+join(", ")
+["a","b,c,d","e"]
+"a, b,c,d, e"
+
+join(" ")
+["a",1,2.3,true,null,false]
+"a 1 2.3 true false"
+
+[while(.<100; .*2)]
+1
+[1,2,4,8,16,32,64]
+
+[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]
+4
+24
+
+recurse(.foo[])
+{"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]}
+{"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}
+{"foo":[]}
+{"foo":[{"foo":[]}]}
+{"foo":[]}
+
+recurse
+{"a":0,"b":[1]}
+{"a":0,"b":[1]}
+0
+[1]
+1
+
+recurse(. * .; . < 20)
+2
+2
+4
+16
+
+walk(if type == "array" then sort else . end)
+[[4, 1, 7], [8, 5, 2], [3, 6, 9]]
+[[1,4,7],[2,5,8],[3,6,9]]
+
+walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )
+[ { "_a": { "__b": 2 } } ]
+[{"a":{"b":2}}]
+
+$ENV.PAGER
+null
+"less"
+
+env.PAGER
+null
+"less"
+
+transpose
+[[1], [2,3]]
+[[1,2],[null,3]]
+
+bsearch(0)
+[0,1]
+0
+
+bsearch(0)
+[1,2,3]
+-1
+
+bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end
+[1,2,3]
+[1,2,3,4]
+
+"The input was \(.), which is one less than \(.+1)"
+42
+"The input was 42, which is one less than 43"
+
+[.[]|tostring]
+[1, "foo", ["foo"]]
+["1","foo","[\"foo\"]"]
+
+[.[]|tojson]
+[1, "foo", ["foo"]]
+["1","\"foo\"","[\"foo\"]"]
+
+[.[]|tojson|fromjson]
+[1, "foo", ["foo"]]
+[1,"foo",["foo"]]
+
+@html
+"This works if x < y"
+"This works if x &lt; y"
+
+@sh "echo \(.)"
+"O'Hara's Ale"
+"echo 'O'\\''Hara'\\''s Ale'"
+
+@base64
+"This is a message"
+"VGhpcyBpcyBhIG1lc3NhZ2U="
+
+@base64d
+"VGhpcyBpcyBhIG1lc3NhZ2U="
+"This is a message"
+
+fromdate
+"2015-03-05T23:51:47Z"
+1425599507
+
+strptime("%Y-%m-%dT%H:%M:%SZ")
+"2015-03-05T23:51:47Z"
+[2015,2,5,23,51,47,4,63]
+
+strptime("%Y-%m-%dT%H:%M:%SZ")|mktime
+"2015-03-05T23:51:47Z"
+1425599507
+
+.[] == 1
+[1, 1.0, "1", "banana"]
+true
+true
+false
+false
+
+if . == 0 then "zero" elif . == 1 then "one" else "many" end
+2
+"many"
+
+. < 5
+2
+true
+
+42 and "a string"
+null
+true
+
+(true, false) or false
+null
+true
+false
+
+(true, true) and (true, false)
+null
+true
+false
+true
+false
+
+[true, false | not]
+null
+[false, true]
+
+.foo // 42
+{"foo": 19}
+19
+
+.foo // 42
+{}
+42
+
+try .a catch ". is not an object"
+true
+". is not an object"
+
+[.[]|try .a]
+[{}, true, {"a":1}]
+[null, 1]
+
+try error("some exception") catch .
+true
+"some exception"
+
+[.[]|(.a)?]
+[{}, true, {"a":1}]
+[null, 1]
+
+test("foo")
+"foo"
+true
+
+.[] | test("a b c # spaces are ignored"; "ix")
+["xabcd", "ABC"]
+true
+true
+
+match("(abc)+"; "g")
+"abc abc"
+{"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}
+{"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}
+
+match("foo")
+"foo bar foo"
+{"offset": 0, "length": 3, "string": "foo", "captures": []}
+
+match(["foo", "ig"])
+"foo bar FOO"
+{"offset": 0, "length": 3, "string": "foo", "captures": []}
+{"offset": 8, "length": 3, "string": "FOO", "captures": []}
+
+match("foo (?<bar123>bar)? foo"; "ig")
+"foo bar foo foo foo"
+{"offset": 0, "length": 11, "string": "foo bar foo", "captures": [{"offset": 4, "length": 3, "string": "bar", "name": "bar123"}]}
+{"offset": 12, "length": 8, "string": "foo foo", "captures": [{"offset": -1, "length": 0, "string": null, "name": "bar123"}]}
+
+[ match("."; "g")] | length
+"abc"
+3
+
+capture("(?<a>[a-z]+)-(?<n>[0-9]+)")
+"xyzzy-14"
+{ "a": "xyzzy", "n": "14" }
+
+.bar as $x | .foo | . + $x
+{"foo":10, "bar":200}
+210
+
+. as $i|[(.*2|. as $i| $i), $i]
+5
+[10,5]
+
+. as [$a, $b, {c: $c}] | $a + $b + $c
+[2, 3, {"c": 4, "d": 5}]
+9
+
+.[] as [$a, $b] | {a: $a, b: $b}
+[[0], [0, 1], [2, 1, 0]]
+{"a":0,"b":null}
+{"a":0,"b":1}
+{"a":2,"b":1}
+
+.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}
+[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]
+{"a":1,"b":2,"d":3,"e":4}
+{"a":1,"b":2,"d":3,"e":4}
+
+.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}
+[{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}]
+{"a":1,"b":2,"d":3,"e":null}
+{"a":1,"b":2,"d":null,"e":4}
+
+.[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end
+[[3]]
+{"a":null,"b":3}
+
+def addvalue(f): . + [f]; map(addvalue(.[0]))
+[[1,2],[10,20]]
+[[1,2,1], [10,20,10]]
+
+def addvalue(f): f as $x | map(. + $x); addvalue(.[0])
+[[1,2],[10,20]]
+[[1,2,1,2], [10,20,1,2]]
+
+reduce .[] as $item (0; . + $item)
+[10,2,5,3]
+20
+
+isempty(empty)
+null
+true
+
+[limit(3;.[])]
+[0,1,2,3,4,5,6,7,8,9]
+[0,1,2]
+
+[first(range(.)), last(range(.)), nth(./2; range(.))]
+10
+[0,9,5]
+
+[range(.)]|[first, last, nth(5)]
+10
+[0,9,5]
+
+[foreach .[] as $item ([[],[]]; if $item == null then [[],.[0]] else [(.[0] + [$item]),[]] end; if $item == null then .[1] else empty end)]
+[1,2,3,4,null,"a","b",null]
+[[1,2,3,4],["a","b"]]
+
+def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)
+null
+0
+3
+6
+9
+
+def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]
+1
+[1,2,4,8,16,32,64]
+
+[1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])]
+1
+[[[0],2],[[0]]]
+
+fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))
+null
+[2]
+
+. as $dot|fromstream($dot|tostream)|.==$dot
+[0,[1,{"a":1},{"b":2}]]
+true
+
+(..|select(type=="boolean")) |= if . then 1 else 0 end
+[true,false,[5,true,[true,[false]],false]]
+[1,0,[5,1,[1,[0]],0]]
+
+.foo += 1
+{"foo": 42}
+{"foo": 43}
+

View File

@ -1,244 +0,0 @@
commit fead9669cb67badb22789d3ed1888779ed85c679
Author: Tomas Halman <thalman@redhat.com>
Date: Thu Mar 9 11:34:44 2023 +0100
Test that jq works in threads
This patch implements test that searches a key in simple
json in pthread.
diff -up jq-1.6/src/jq_test.c.orig jq-1.6/src/jq_test.c
--- jq-1.6/src/jq_test.c.orig 2023-03-09 14:02:16.980062057 +0100
+++ jq-1.6/src/jq_test.c 2023-03-09 14:03:38.347017032 +0100
@@ -2,12 +2,17 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
#include "jv.h"
#include "jq.h"
static void jv_test();
static void run_jq_tests(jv, int, FILE *, int, int);
-
+#ifdef HAVE_PTHREAD
+static void run_jq_pthread_tests();
+#endif
int jq_testsuite(jv libdirs, int verbose, int argc, char* argv[]) {
FILE *testdata = stdin;
@@ -32,6 +37,9 @@ int jq_testsuite(jv libdirs, int verbose
}
}
run_jq_tests(libdirs, verbose, testdata, skip, take);
+#ifdef HAVE_PTHREAD
+ run_jq_pthread_tests();
+#endif
return 0;
}
@@ -105,7 +113,7 @@ static void run_jq_tests(jv lib_dirs, in
if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n'))
break;
}
-
+
must_fail = 0;
check_msg = 0;
@@ -229,7 +237,7 @@ static void run_jq_tests(jv lib_dirs, in
total_skipped = tests_to_skip - skip;
}
- printf("%d of %d tests passed (%d malformed, %d skipped)\n",
+ printf("%d of %d tests passed (%d malformed, %d skipped)\n",
passed, tests, invalid, total_skipped);
if (skip > 0) {
@@ -241,6 +249,88 @@ static void run_jq_tests(jv lib_dirs, in
}
+/// pthread regression test
+#ifdef HAVE_PTHREAD
+#define NUMBER_OF_THREADS 3
+struct test_pthread_data {
+ int result;
+};
+
+static int test_pthread_jq_parse(jq_state *jq, struct jv_parser *parser)
+{
+ int rv = 0;
+ jv value;
+
+ value = jv_parser_next(parser);
+ while (jv_is_valid(value)) {
+ jq_start(jq, value, 0);
+ jv result = jq_next(jq);
+
+ while (jv_is_valid(result)) {
+ jv_free(result);
+ result = jq_next(jq);
+ }
+ jv_free(result);
+ value = jv_parser_next(parser);
+ }
+ jv_free(value);
+ return rv;
+}
+
+static void *test_pthread_run(void *ptr) {
+ int rv;
+ jq_state *jq;
+ const char *prg = ".data";
+ const char *buf = "{ \"data\": 1 }";
+ struct test_pthread_data *data = ptr;
+
+ jq = jq_init();
+ if (jq_compile(jq, prg) == 0) {
+ jq_teardown(&jq);
+ return NULL;
+ }
+
+ struct jv_parser *parser = jv_parser_new(0);
+ jv_parser_set_buf(parser, buf, strlen(buf), 0);
+ rv = test_pthread_jq_parse(jq, parser);
+
+ data->result = rv;
+
+ jv_parser_free(parser);
+ jq_teardown(&jq);
+ return NULL;
+}
+
+static void run_jq_pthread_tests() {
+ pthread_t threads[NUMBER_OF_THREADS];
+ struct test_pthread_data data[NUMBER_OF_THREADS];
+ int createerror;
+ int a;
+
+ memset(&threads, 0, sizeof(threads));
+ memset(&data, 0, sizeof(data));
+
+ // Create all threads
+ for (a = 0; a < NUMBER_OF_THREADS; ++a) {
+ createerror = pthread_create(&threads[a], NULL, test_pthread_run, &data[a]);
+ assert(createerror == 0);
+ }
+
+ // wait for all threads
+ for(a = 0; a < NUMBER_OF_THREADS; ++a) {
+ if (threads[a] != 0) {
+ pthread_join(threads[a], NULL);
+ }
+ }
+
+ // check results
+ for(a = 0; a < NUMBER_OF_THREADS; ++a) {
+ assert(data[a].result == 0);
+ }
+}
+#endif // HAVE_PTHREAD
+
+
static void jv_test() {
/// JSON parser regression tests
{
commit f05c5bb521f404592b137e02a1b8abd50da87ca3
Author: Tomas Halman <thalman@redhat.com>
Date: Wed Mar 1 20:07:28 2023 +0100
Fix segmentation fault when using jq in threads
In previous code nomem_handler in jv_alloc.c is called only once
and therefore the structure is not initialized for second and
following threads.
This leads to segmentation fault in multi-threading environment.
This patch moves initialization of nomem_handler out of the
pthread_once call.
diff -up jq-1.6/src/jv_alloc.c.orig jq-1.6/src/jv_alloc.c
--- jq-1.6/src/jv_alloc.c.orig 2018-11-02 02:49:29.000000000 +0100
+++ jq-1.6/src/jv_alloc.c 2023-03-09 14:13:47.810177037 +0100
@@ -45,9 +45,11 @@ static void memory_exhausted() {
#ifdef HAVE_PTHREAD_KEY_CREATE
#include <pthread.h>
-pthread_key_t nomem_handler_key;
-pthread_once_t mem_once = PTHREAD_ONCE_INIT;
+static pthread_key_t nomem_handler_key;
+static pthread_once_t mem_once = PTHREAD_ONCE_INIT;
+/* tsd_fini is called on application exit */
+/* it clears the nomem_handler allocated in the main thread */
static void tsd_fini(void) {
struct nomem_handler *nomem_handler;
nomem_handler = pthread_getspecific(nomem_handler_key);
@@ -57,30 +59,45 @@ static void tsd_fini(void) {
}
}
+/* The tsd_fini_thread is a destructor set by calling */
+/* pthread_key_create(&nomem_handler_key, tsd_fini_thread) */
+/* It is called when thread ends */
+static void tsd_fini_thread(void *nomem_handler) {
+ free(nomem_handler);
+}
+
static void tsd_init(void) {
- if (pthread_key_create(&nomem_handler_key, NULL) != 0) {
- fprintf(stderr, "error: cannot create thread specific key");
+ if (pthread_key_create(&nomem_handler_key, tsd_fini_thread) != 0) {
+ fprintf(stderr, "jq: error: cannot create thread specific key");
abort();
}
if (atexit(tsd_fini) != 0) {
- fprintf(stderr, "error: cannot set an exit handler");
+ fprintf(stderr, "jq: error: cannot set an exit handler");
abort();
}
- struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
- if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
- fprintf(stderr, "error: cannot set thread specific data");
- abort();
+}
+
+static void tsd_init_nomem_handler(void)
+{
+ if (pthread_getspecific(nomem_handler_key) == NULL) {
+ struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
+ if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
+ fprintf(stderr, "jq: error: cannot set thread specific data");
+ abort();
+ }
}
}
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
pthread_once(&mem_once, tsd_init); // cannot fail
+ tsd_init_nomem_handler();
+
struct nomem_handler *nomem_handler;
nomem_handler = pthread_getspecific(nomem_handler_key);
if (nomem_handler == NULL) {
handler(data);
- fprintf(stderr, "error: cannot allocate memory\n");
+ fprintf(stderr, "jq: error: cannot allocate memory\n");
abort();
}
nomem_handler->handler = handler;
@@ -91,6 +108,8 @@ static void memory_exhausted() {
struct nomem_handler *nomem_handler;
pthread_once(&mem_once, tsd_init);
+ tsd_init_nomem_handler();
+
nomem_handler = pthread_getspecific(nomem_handler_key);
if (nomem_handler)
nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +0,0 @@
diff -up jq-1.6/src/jq_test.c.orig jq-1.6/src/jq_test.c
--- jq-1.6/src/jq_test.c.orig 2024-05-03 11:47:47.403617188 +0200
+++ jq-1.6/src/jq_test.c 2024-05-03 11:48:46.569675199 +0200
@@ -16,6 +16,7 @@ static void run_jq_pthread_tests();
int jq_testsuite(jv libdirs, int verbose, int argc, char* argv[]) {
FILE *testdata = stdin;
+ const char *testdata_filename = NULL;
int skip = -1;
int take = -1;
jv_test();
@@ -28,18 +29,24 @@ int jq_testsuite(jv libdirs, int verbose
take = atoi(argv[i+1]);
i++;
} else {
- testdata = fopen(argv[i], "r");
- if (!testdata) {
- perror("fopen");
- exit(1);
- }
+ testdata_filename = argv[i];
}
}
}
+ if (testdata_filename) {
+ testdata = fopen(testdata_filename, "r");
+ if (!testdata) {
+ perror("fopen");
+ exit(1);
+ }
+ }
run_jq_tests(libdirs, verbose, testdata, skip, take);
#ifdef HAVE_PTHREAD
run_jq_pthread_tests();
#endif
+ if (testdata_filename) {
+ fclose(testdata);
+ }
return 0;
}
diff -up jq-1.6/src/locfile.c.orig jq-1.6/src/locfile.c
--- jq-1.6/src/locfile.c.orig 2018-11-02 02:49:29.000000000 +0100
+++ jq-1.6/src/locfile.c 2024-05-03 11:15:46.562476303 +0200
@@ -72,6 +72,7 @@ void locfile_locate(struct locfile* l, l
}
jv m1 = jv_string_vfmt(fmt, fmtargs);
+ va_end(fmtargs);
if (!jv_is_valid(m1)) {
jq_report_error(l->jq, m1);
return;

View File

@ -1,6 +0,0 @@
--- !Policy
product_versions:
- rhel-8
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

185
jq.spec
View File

@ -1,29 +1,41 @@
## START: Set by rpmautospec
## (rpmautospec version 0.6.5)
## RPMAUTOSPEC: autorelease, autochangelog
%define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
release_number = 11;
base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
print(release_number + base_release_number - 1);
}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
## END: Set by rpmautospec
# valgrind cannot cope with GCC 13+ SSE4.1 optimizations of strcmp
# https://bugzilla.redhat.com/show_bug.cgi?id=2257546
%bcond check %[!(0%{?rhel} >= 10)]
Name: jq
Version: 1.6
Release: 9%{?dist}
Version: 1.7.1
Release: %autorelease
Summary: Command-line JSON processor
License: MIT and ASL 2.0 and CC-BY and GPLv3
URL: http://stedolan.github.io/jq/
Source0: https://github.com/stedolan/jq/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
Patch0: 0000-jq-decimal-literal-number.patch
Patch1: 0001-iterration-problem-for-non-decimal-string.patch
Patch2: 0002-add-mantest.patch
Patch3: 0003-fix-pthread-segfault.patch
Patch4: 0004-make-jq-fast.patch
Patch5: 0005-sast.patch
URL: https://jqlang.github.io/jq/
Source0: https://github.com/jqlang/jq/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
Patch1: 0001-CVE-2024-23337.patch
Patch3: 0002-CVE-2025-48060.patch
BuildRequires: gcc
BuildRequires: flex
BuildRequires: bison
BuildRequires: chrpath
BuildRequires: oniguruma-devel
%ifarch %{valgrind_arches}
BuildRequires: valgrind
%endif
BuildRequires: make
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: chrpath
%ifnarch s390x
BuildRequires: valgrind
%endif
%description
@ -43,20 +55,20 @@ lightweight and flexible command-line JSON processor
you'd expect.
%package devel
Summary: Development files for %{name}
Requires: %{name}%{?_isa} = %{version}-%{release}
Summary: Development files for %{name}
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
Development files for %{name}
%prep
%autosetup -n %{name}-%{version} -p1
%autosetup -n %{name}-%{name}-%{version} -p1
%build
autoreconf -fi
autoreconf -if
%configure --disable-static
make %{?_smp_mflags}
%make_build
# Docs already shipped in jq's tarball.
# In order to build the manual page, it
# is necessary to install rake, rubygem-ronn
@ -72,73 +84,126 @@ make %{?_smp_mflags}
# $ make real_docs
%install
make DESTDIR=%{buildroot} install
%make_install
find %{buildroot} -name '*.la' -exec rm -f {} ';'
chrpath --delete %{buildroot}/usr/bin/jq
# Delete build-time RPATH that is unnecessary on an installed
# system - rhbz#1987608
chrpath -d %{buildroot}%{_bindir}/%{name}
%if %{with check}
%check
# Valgrind used, so restrict architectures for check
%ifarch %{ix86} x86_64
make check
%endif
%ldconfig_scriptlets
%endif
%files
%license COPYING
%doc AUTHORS COPYING NEWS.md README.md
%{_bindir}/%{name}
%{_libdir}/libjq.so.*
%{_datadir}/man/man1/jq.1.gz
%{_datadir}/doc/jq/AUTHORS
%{_datadir}/doc/jq/COPYING
%{_datadir}/doc/jq/README
%{_datadir}/doc/jq/README.md
%files devel
%{_includedir}/jq.h
%{_includedir}/jv.h
%{_libdir}/libjq.so
%{_libdir}/pkgconfig/libjq.pc
%changelog
* Fri May 3 2024 Tomas Halman <thalman@redhat.com> - 1.6-9
- Fix SAST findings in jq 1.6
- Resolves: RHEL-37827
## START: Generated by rpmautospec
* Mon Jun 30 2025 Tomas Halman <thalman@redhat.com> - 1.7.1-11
- AddressSanitizer: stack-buffer-overflow in jq_fuzz_execute
* Fri Oct 13 2023 Tomas Halman <thalman@redhat.com> - 1.6-8
- Make jq 1.6 fast
- Resolves: RHEL-5052
* Mon Jun 30 2025 Tomas Halman <thalman@redhat.com> - 1.7.1-10
- Fix signed integer overflow in jvp_array_write
* Tue Mar 14 2023 Tomas Halman <thalman@redhat.com> - 1.6-7
- Fix jq segfault when used in threads
- Resolves: rhbz#2092160
* Fri Jun 27 2025 Scott Poore <spoore@redhat.com> - 1.7.1-9
- performance test support glibc preload test
* Fri Nov 4 2022 Tomas Halman <thalman@redhat.com> - 1.6-6
- Add mantest to the gating
- Related: rhbz#2049601
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 1.7.1-8
- Bump release for October 2024 mass rebuild:
* Tue Oct 11 2022 Tomas Halman <thalman@redhat.com> - 1.6-5
- Remove rpath from jq binary
- Related: rhbz#2049601
* Mon Oct 21 2024 Scott Poore <spoore@redhat.com> - 1.7.1-7
- Update upstream tests to disable fedora repos
* Tue Oct 11 2022 Tomas Halman <thalman@redhat.com> - 1.6-4
- Fix iterration problem for non decimal string
- Resolves: rhbz#2049601
* Mon Oct 21 2024 Tomas Halman <thalman@redhat.com> - 1.7.1-6
- Add gating tests configuration
* Mon Oct 4 2021 Tomas Halman <thalman@redhat.com>
- Fix big integers issue
- Resolves: bug#2008717
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 1.7.1-5
- Bump release for June 2024 mass rebuild
* Mon Oct 4 2021 Tomas Halman <thalman@redhat.com>
- Releasing v1.6
- Resolves: bug#1852514
* Wed Jan 24 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.7.1-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Wed Aug 11 2021 Tomas Halman <thalman@redhat.com>
- Publishing devel package
- Resolves: bug#1908928
* Wed Jan 24 2024 Yaakov Selkowitz <yselkowi@redhat.com> - 1.7.1-3
- Disable tests on RHEL 10
* Sat Aug 11 2018 Troy Dawson <tdawson@redhat.com>
- Fix typo: s390 -> s390x
- Related: bug#1614611
* Sat Jan 20 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.7.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Fri Jan 05 2024 jonathanspw <jonathan@almalinux.org> - 1.7.1-1
- update to 1.7.1 rhbz#2252340
* Fri Sep 08 2023 Mikel Olasagasti Uranga <mikel@olasagasti.info> - 1.7-1
- Update to 1.7
* Thu Jul 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-17
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-16
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Fri Jan 13 2023 Florian Weimer <fweimer@redhat.com> - 1.6-15
- Port configure script to C99
* Thu Jul 21 2022 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-14
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Fri Mar 11 2022 Neal Gompa <ngompa@fedoraproject.org> - 1.6-13
- Use make macros
- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro
* Tue Mar 08 2022 Davide Cavalca <dcavalca@fedoraproject.org> - 1.6-12
- Backport PR#2400 to fix iteration for non-decimal strings (rhbz#2017285)
* Thu Jan 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Wed Sep 29 2021 Davide Cavalca <dcavalca@fedoraproject.org> - 1.6-10
- Backport PR#1752 to fix an integer logic issue (rhbz#2008979)
* Thu Aug 12 2021 Lon Hohberger <lon@redhat.com> - 1.6-9
- Drop build-time RPATH from jq binary (rhbz#1987608)
* Thu Jul 22 2021 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Sat Dec 05 2020 Richard W.M. Jones <rjones@redhat.com> - 1.6-6
- Use correct valgrind_arches macro to check for valgrind.
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.6-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Thu Nov 08 2018 David Fetter <david@fetter.org> - 1.6-1
- Upstream 1.6.0
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.5-13
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Sun Apr 01 2018 Mamoru TASAKA <mtasaka@fedoraproject.org> - 1.5-12
- Rebuild against oniguruma 6.8.1
@ -190,3 +255,5 @@ make check
* Fri Oct 18 2013 Flavio Percoco <flavio@redhat.com> - 1.3-1
- Initial package release.
## END: Generated by rpmautospec

View File

@ -1,23 +0,0 @@
summary: Run gating tests
discover:
how: fmf
dist-git-source: true
dist-git-type: centos
prepare:
- how: install
package:
- dnf-plugins-core
- https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
- how: shell
script: /usr/bin/crb enable
- how: install
package:
- jq
- jq-devel
- gcc
- wget
- how: shell
script: dnf config-manager --disable epel*
execute:
how: tmt

View File

@ -1 +1 @@
SHA512 (jq-1.6.tar.gz) = f5ae8be558ca2ff15324c378d623106b74bd0823be50835e23548584aa1eb24eb81f8f054693d5d3fe44f157d0735c5f0f40b9f21899ba068f2a11d1345ace19
SHA512 (jq-1.7.1.tar.gz) = af9c444e5306423182f467a53acdf45bb8aefa058a47f490ce16395f0aebfb7627e3843f65e96f41cd9d4b72b8ad274ab0bdb061abc6990b1158f86d2256d4ec

View File

@ -1,20 +0,0 @@
#!/bin/bash
export LC_ALL=C
stress_jq() {
`which time` -p -f '%e\n' bash -c 'for i in `seq 1 1000` ; do echo '"'"'{"foo":"bar"}'"'"' | jq '"'"'has("bar")'"'"' > /dev/null ; done' 2>&1 | cut -d. -f1
}
FAIL=0
TIME=`stress_jq`
echo -n "Test jqspeed ... "
if [ $TIME -gt 8 ] ; then
echo "failed"
FAIL=1
else
echo "ok"
fi
echo "Runtime: ${TIME}s "
exit $FAIL

View File

@ -1,6 +0,0 @@
summary: Run jq performance/speed test
require:
- jq
- which
- time
test: ./jqspeed.sh

View File

View File

@ -1,5 +0,0 @@
---
standard-inventory-qcow2:
qemu:
m: 2G

View File

@ -1,19 +0,0 @@
#!/bin/sh
FAIL=0
# Test for segfault in multithreaded environment
gcc -o test_segfault test_segfault_with_multithreaded_env.c -lpthread -ljq && \
./test_segfault
RET=$?
echo -n "Test jqsegfault ... "
if [ $RET != 0 ]; then
echo "failed"
FAIL=1
else
echo "ok"
fi
exit $FAIL

View File

@ -1,8 +0,0 @@
summary: Run segfault threads test
require:
- wget
- dnf-utils
- gcc
- jq
- jq-devel
test: ./jqsegfault.sh

View File

@ -1,90 +0,0 @@
#include <stdlib.h>
#include <jq.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int my_jq_parse(jq_state *jq, struct jv_parser *parser)
{
int rv = 0;
jv value;
value = jv_parser_next(parser);
while (jv_is_valid(value)) {
jq_start(jq, value, 0);
jv result;
while (jv_is_valid(result = jq_next(jq))) {
jv dumped = jv_dump_string(result, 0);
const char *str = jv_string_value(dumped);
printf("dumped: %s\n", str);
}
jv_free(result);
value = jv_parser_next(parser);
}
if (jv_invalid_has_msg(jv_copy(value))) {
jv msg = jv_invalid_get_msg(value);
printf("invalid: %s\n", jv_string_value(msg));
jv_free(msg);
rv = 1;
} else {
jv_free(value);
}
return rv;
}
void *run(void *not_used) {
int rv;
jq_state *jq;
const char *prg = ".data";
jq = jq_init();
printf("jq_init jq: %p prg: %s\n", jq, prg);
if (jq_compile(jq, prg) == 0) {
jq_teardown(&jq);
return NULL;
}
printf("compiled\n");
struct jv_parser *parser = jv_parser_new(0);
const char *buf = "{ \"data\": 1 }";
jv_parser_set_buf(parser, buf, strlen(buf), 0);
rv = my_jq_parse(jq, parser);
if (rv != 0) {
printf("my_jq_parse failed!\n");
}
jv_parser_free(parser);
jq_teardown(&jq);
return NULL;
}
#define THREADS 2
/* calling run() twice works fine */
/* calling them in threads causes core-dump */
int main (int argc, char *argv[])
{
pthread_t threads[THREADS];
int createerror;
int a;
memset(&threads, 0, sizeof(threads));
for (a = 0; a < THREADS; ++a) {
// sleep(1); // < if you want to run threads sequentionally
createerror = pthread_create(&threads[a], NULL, run, NULL);
if (createerror) {
printf("create thread error %d\n", a);
}
}
for(a = 0; a < THREADS; ++a) {
if (threads[a] != 0) {
pthread_join(threads[a], NULL);
}
}
return 0;
}

View File

@ -1,27 +0,0 @@
---
- hosts: localhost
roles:
- role: standard-test-source
tags:
- always
- role: standard-test-basic
tags:
- classic
required_packages:
- jq
- gcc
- wget
- jq-devel
- valgrind
- rubygem-rake
tests:
- upstream:
dir: upstream
run: ./jqtests.sh
- segfault:
dir: segfault
run: ./jqsegfault.sh
- performance:
dir: performance
run: ./jqspeed.sh

View File

@ -1,48 +0,0 @@
#!/bin/sh
die () {
echo "$1" >&2
exit 1
}
# If source not found, download it with dnf
if [ ! -d ./source ]; then
# Extract source from srpm
dnf download --source jq && \
rpm2cpio jq*.rpm|cpio -id && \
mkdir source && \
tar -zxf jq-*.tar.gz -C source --strip-components=1
if [ $? != 0 ]; then
echo "Failed to download upstream tests"
exit 1
fi
fi
pushd ./source || die "missing source directory"
rm -f jq tests/*.log 2>/dev/null
ln -s /usr/bin/jq || die "failed to link jq binary"
FAIL=0
# run the tests
# List of tests is taken from Makefile
TESTS="tests/optionaltest tests/mantest tests/jqtest tests/onigtest tests/shtest tests/utf8test tests/base64test"
for t in $TESTS; do
echo -n "Test $t ... "
./${t} >"${t}.log" 2>&1
RET=$?
if [ $RET = 0 ]; then
echo "ok"
else
echo "failed"
echo "-------------------- ${t}.log start -----------------------------"
cat "${t}.log"
echo "-------------------- ${t}.log end -----------------------------"
FAIL=1
fi
done
popd # exit SOURCE_DIR
exit $FAIL

View File

@ -1,11 +0,0 @@
summary: Run jq gating tests
require:
- wget
- dnf-utils
- gcc
- jq
- jq-devel
- valgrind
- diffutils
test: ./jqtests.sh
duration: 30m