Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 753826117d | |||
| eb87df2276 | |||
| 349fdd5996 |
@ -1 +0,0 @@
|
||||
1
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -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
206
0001-CVE-2024-23337.patch
Normal 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
|
||||
#
|
||||
@ -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
141
0002-CVE-2025-48060.patch
Normal 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}
|
||||
@ -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 < 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}
|
||||
+
|
||||
@ -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
@ -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;
|
||||
@ -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
185
jq.spec
@ -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
|
||||
|
||||
@ -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
|
||||
2
sources
2
sources
@ -1 +1 @@
|
||||
SHA512 (jq-1.6.tar.gz) = f5ae8be558ca2ff15324c378d623106b74bd0823be50835e23548584aa1eb24eb81f8f054693d5d3fe44f157d0735c5f0f40b9f21899ba068f2a11d1345ace19
|
||||
SHA512 (jq-1.7.1.tar.gz) = af9c444e5306423182f467a53acdf45bb8aefa058a47f490ce16395f0aebfb7627e3843f65e96f41cd9d4b72b8ad274ab0bdb061abc6990b1158f86d2256d4ec
|
||||
|
||||
@ -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
|
||||
@ -1,6 +0,0 @@
|
||||
summary: Run jq performance/speed test
|
||||
require:
|
||||
- jq
|
||||
- which
|
||||
- time
|
||||
test: ./jqspeed.sh
|
||||
@ -1,5 +0,0 @@
|
||||
---
|
||||
|
||||
standard-inventory-qcow2:
|
||||
qemu:
|
||||
m: 2G
|
||||
@ -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
|
||||
@ -1,8 +0,0 @@
|
||||
summary: Run segfault threads test
|
||||
require:
|
||||
- wget
|
||||
- dnf-utils
|
||||
- gcc
|
||||
- jq
|
||||
- jq-devel
|
||||
test: ./jqsegfault.sh
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -1,11 +0,0 @@
|
||||
summary: Run jq gating tests
|
||||
require:
|
||||
- wget
|
||||
- dnf-utils
|
||||
- gcc
|
||||
- jq
|
||||
- jq-devel
|
||||
- valgrind
|
||||
- diffutils
|
||||
test: ./jqtests.sh
|
||||
duration: 30m
|
||||
Loading…
Reference in New Issue
Block a user