Skip to content

Commit 7df7524

Browse files
authored
Merge branch 'jqlang:master' into master
2 parents f09d34f + 9d6efec commit 7df7524

23 files changed

+396
-265
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ jobs:
8888
./configure \
8989
--host=${{ matrix.CC }} \
9090
--disable-docs \
91-
--disable-valgrind \
9291
--with-oniguruma=builtin \
9392
--enable-static \
9493
--enable-all-static \
@@ -154,7 +153,6 @@ jobs:
154153
./configure \
155154
--host="${{ matrix.target }}$(uname -r)" \
156155
--disable-docs \
157-
--disable-valgrind \
158156
--with-oniguruma=builtin \
159157
--enable-static \
160158
--enable-all-static \
@@ -230,7 +228,6 @@ jobs:
230228
autoreconf -i
231229
./configure \
232230
--disable-docs \
233-
--disable-valgrind \
234231
--with-oniguruma=builtin \
235232
--disable-shared \
236233
--enable-static \
@@ -276,7 +273,6 @@ jobs:
276273
autoreconf -i
277274
./configure \
278275
--disable-docs \
279-
--disable-valgrind \
280276
--with-oniguruma=builtin
281277
make distcheck
282278
make dist dist-zip

.github/workflows/oniguruma.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
autoreconf -i
2323
./configure \
2424
--disable-docs \
25+
--enable-valgrind \
2526
--with-oniguruma=yes
2627
make -j"$(nproc)"
2728
file ./jq
@@ -54,6 +55,7 @@ jobs:
5455
autoreconf -i
5556
./configure \
5657
--disable-docs \
58+
--enable-valgrind \
5759
--with-oniguruma=no
5860
make -j"$(nproc)"
5961
file ./jq

.github/workflows/scanbuild.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
MAKEVARS: ${{ matrix.makevars }}
5050
run: |
5151
autoreconf -i
52-
./configure --with-oniguruma=builtin $COVERAGE
52+
./configure --with-oniguruma=builtin --enable-valgrind $COVERAGE
5353
scan-build --keep-going make -j4
5454
- name: Test
5555
env:

.github/workflows/valgrind.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
autoreconf -i
2323
./configure \
2424
--disable-docs \
25+
--enable-valgrind \
2526
--with-oniguruma=builtin
2627
make -j"$(nproc)"
2728
file ./jq

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ COPY . /app
1919
RUN autoreconf -i \
2020
&& ./configure \
2121
--disable-docs \
22-
--disable-valgrind \
2322
--with-oniguruma=builtin \
2423
--enable-static \
2524
--enable-all-static \

Makefile.am

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,18 @@ endif
6565

6666
include_HEADERS = src/jv.h src/jq.h
6767

68-
if ENABLE_UBSAN
69-
AM_CFLAGS += -fsanitize=undefined
70-
endif
71-
7268
AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/vendor
7369

74-
### Running tests under Valgrind
70+
### Address sanitizer (ASan)
7571

7672
if ENABLE_ASAN
7773
AM_CFLAGS += -fsanitize=address
78-
NO_VALGRIND = 1
79-
else
80-
if ENABLE_VALGRIND
81-
NO_VALGRIND =
82-
else
83-
NO_VALGRIND = 1
8474
endif
75+
76+
### Undefined Behavior Sanitizer
77+
78+
if ENABLE_UBSAN
79+
AM_CFLAGS += -fsanitize=undefined
8580
endif
8681

8782
### Code coverage with gcov
@@ -127,7 +122,11 @@ TESTS = tests/mantest tests/jqtest tests/shtest tests/utf8test tests/base64test
127122
if !WIN32
128123
TESTS += tests/optionaltest
129124
endif
130-
AM_TESTS_ENVIRONMENT = JQ=$(abs_builddir)/jq NO_VALGRIND=$(NO_VALGRIND)
125+
126+
AM_TESTS_ENVIRONMENT = JQ=$(abs_builddir)/jq
127+
if ENABLE_VALGRIND
128+
AM_TESTS_ENVIRONMENT += ENABLE_VALGRIND=1
129+
endif
131130

132131
# This is a magic make variable that causes it to treat tests/man.test as a
133132
# DATA-type dependency for the check target. As a result, it will attempt to

configure.ac

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ if test "$USE_MAINTAINER_MODE" = yes; then
3939
AC_CHECK_PROGS(LEX, flex lex)
4040
fi
4141

42-
dnl Check for valgrind
43-
AC_CHECK_PROGS(valgrind_cmd, valgrind)
44-
if test "x$valgrind_cmd" = "x" ; then
45-
AC_MSG_WARN([valgrind is required to test jq.])
46-
fi
4742
AC_CHECK_FUNCS(memmem)
4843

4944
AC_CHECK_HEADER("sys/cygwin.h", [have_cygwin=1;])
@@ -54,10 +49,9 @@ dnl Running tests with Valgrind is slow. It is faster to iterate on
5449
dnl code without Valgrind until tests pass, then enable Valgrind and
5550
dnl fix leaks.
5651
AC_ARG_ENABLE([valgrind],
57-
AS_HELP_STRING([--disable-valgrind],[do not run tests under Valgrind]))
52+
AS_HELP_STRING([--enable-valgrind],[enable Valgrind during testing]))
5853

59-
dnl Running tests with Valgrind is slow; address sanitizer (ASAN) is
60-
dnl faster.
54+
dnl Address sanitizer (ASan)
6155
AC_ARG_ENABLE([asan],
6256
AS_HELP_STRING([--enable-asan],[enable address sanitizer]))
6357

@@ -114,7 +108,7 @@ AS_IF([test "x$enable_decnum" != "xno"],[
114108
AC_DEFINE([USE_DECNUM], 1, [Define to enable decnum support.])
115109
])
116110

117-
AM_CONDITIONAL([ENABLE_VALGRIND], [test "x$enable_valgrind" != xno])
111+
AM_CONDITIONAL([ENABLE_VALGRIND], [test "x$enable_valgrind" = xyes])
118112
AM_CONDITIONAL([ENABLE_ASAN], [test "x$enable_asan" = xyes])
119113
AM_CONDITIONAL([ENABLE_UBSAN], [test "x$enable_ubsan" = xyes])
120114
AM_CONDITIONAL([ENABLE_GCOV], [test "x$enable_gcov" = xyes])
@@ -291,7 +285,6 @@ AC_SUBST(onig_LDFLAGS)
291285

292286
AM_CONDITIONAL([BUILD_ONIGURUMA], [test "x$build_oniguruma" = xyes])
293287
AM_CONDITIONAL([WITH_ONIGURUMA], [test "x$with_oniguruma" != xno])
294-
AC_SUBST([BUNDLER], ["$bundle_cmd"])
295288

296289
AC_CONFIG_MACRO_DIRS([config/m4 m4])
297290
AC_CONFIG_HEADERS([src/config.h])

src/builtin.c

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,12 @@
55
# define _XPG6
66
# define __EXTENSIONS__
77
#endif
8+
#ifdef __OpenBSD__
9+
# define _BSD_SOURCE
10+
#endif
811
#include <sys/time.h>
912
#include <stdlib.h>
1013
#include <stddef.h>
11-
#ifdef HAVE_ALLOCA_H
12-
# include <alloca.h>
13-
#elif !defined alloca
14-
# ifdef __GNUC__
15-
# define alloca __builtin_alloca
16-
# elif defined _MSC_VER
17-
# include <malloc.h>
18-
# define alloca _alloca
19-
# elif !defined HAVE_ALLOCA
20-
# ifdef __cplusplus
21-
extern "C"
22-
# endif
23-
void *alloca (size_t);
24-
# endif
25-
#endif
2614
#include <assert.h>
2715
#include <ctype.h>
2816
#include <limits.h>
@@ -340,21 +328,10 @@ jv binop_multiply(jv a, jv b) {
340328
str = b;
341329
num = a;
342330
}
343-
jv res;
344331
double d = jv_number_value(num);
345-
if (d < 0 || isnan(d)) {
346-
res = jv_null();
347-
} else {
348-
int n = d;
349-
size_t alen = jv_string_length_bytes(jv_copy(str));
350-
res = jv_string_empty(alen * n);
351-
for (; n > 0; n--) {
352-
res = jv_string_append_buf(res, jv_string_value(str), alen);
353-
}
354-
}
355-
jv_free(str);
356332
jv_free(num);
357-
return res;
333+
return jv_string_repeat(str,
334+
d < 0 || isnan(d) ? -1 : d > INT_MAX ? INT_MAX : (int)d);
358335
} else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) {
359336
return jv_object_merge_recursive(a, b);
360337
} else {
@@ -494,7 +471,7 @@ static jv f_length(jq_state *jq, jv input) {
494471
} else if (jv_get_kind(input) == JV_KIND_STRING) {
495472
return jv_number(jv_string_length_codepoints(input));
496473
} else if (jv_get_kind(input) == JV_KIND_NUMBER) {
497-
jv r = jv_number(fabs(jv_number_value(input)));
474+
jv r = jv_number_abs(input);
498475
jv_free(input);
499476
return r;
500477
} else if (jv_get_kind(input) == JV_KIND_NULL) {
@@ -757,9 +734,12 @@ static jv f_format(jq_state *jq, jv input, jv fmt) {
757734
input = f_tostring(jq, input);
758735
const unsigned char* data = (const unsigned char*)jv_string_value(input);
759736
int len = jv_string_length_bytes(jv_copy(input));
737+
if (len == 0) {
738+
jv_free(input);
739+
return jv_string("");
740+
}
760741
size_t decoded_len = (3 * (size_t)len) / 4; // 3 usable bytes for every 4 bytes of input
761742
char *result = jv_mem_calloc(decoded_len, sizeof(char));
762-
memset(result, 0, decoded_len * sizeof(char));
763743
uint32_t ri = 0;
764744
int input_bytes_read=0;
765745
uint32_t code = 0;
@@ -879,6 +859,24 @@ static jv f_group_by_impl(jq_state *jq, jv input, jv keys) {
879859
}
880860
}
881861

862+
static jv f_unique(jq_state *jq, jv input) {
863+
if (jv_get_kind(input) == JV_KIND_ARRAY) {
864+
return jv_unique(input, jv_copy(input));
865+
} else {
866+
return type_error(input, "cannot be sorted, as it is not an array");
867+
}
868+
}
869+
870+
static jv f_unique_by_impl(jq_state *jq, jv input, jv keys) {
871+
if (jv_get_kind(input) == JV_KIND_ARRAY &&
872+
jv_get_kind(keys) == JV_KIND_ARRAY &&
873+
jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) {
874+
return jv_unique(input, keys);
875+
} else {
876+
return type_error2(input, keys, "cannot be sorted, as they are not both arrays");
877+
}
878+
}
879+
882880
#ifdef HAVE_LIBONIG
883881
static int f_match_name_iter(const UChar* name, const UChar *name_end, int ngroups,
884882
int *groups, regex_t *reg, void *arg) {
@@ -1758,16 +1756,16 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
17581756
return ret_error(b, jv_string("strftime/1 requires parsed datetime inputs"));
17591757

17601758
const char *fmt = jv_string_value(b);
1761-
size_t alloced = strlen(fmt) + 100;
1762-
char *buf = alloca(alloced);
1759+
size_t max_size = strlen(fmt) + 100;
1760+
char *buf = jv_mem_alloc(max_size);
17631761
#ifdef __APPLE__
17641762
/* Apple Libc (as of version 1669.40.2) contains a bug which causes it to
17651763
* ignore the `tm.tm_gmtoff` in favor of the global timezone. To print the
17661764
* proper timezone offset we temporarily switch the TZ to UTC. */
17671765
char *tz = (tz = getenv("TZ")) != NULL ? strdup(tz) : NULL;
17681766
setenv("TZ", "UTC", 1);
17691767
#endif
1770-
size_t n = strftime(buf, alloced, fmt, &tm);
1768+
size_t n = strftime(buf, max_size, fmt, &tm);
17711769
#ifdef __APPLE__
17721770
if (tz) {
17731771
setenv("TZ", tz, 1);
@@ -1778,9 +1776,13 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
17781776
#endif
17791777
jv_free(b);
17801778
/* POSIX doesn't provide errno values for strftime() failures; weird */
1781-
if (n == 0 || n > alloced)
1779+
if ((n == 0 && *fmt) || n > max_size) {
1780+
free(buf);
17821781
return jv_invalid_with_msg(jv_string("strftime/1: unknown system failure"));
1783-
return jv_string(buf);
1782+
}
1783+
jv ret = jv_string_sized(buf, n);
1784+
free(buf);
1785+
return ret;
17841786
}
17851787
#else
17861788
static jv f_strftime(jq_state *jq, jv a, jv b) {
@@ -1803,14 +1805,18 @@ static jv f_strflocaltime(jq_state *jq, jv a, jv b) {
18031805
if (!jv2tm(a, &tm, 1))
18041806
return ret_error(b, jv_string("strflocaltime/1 requires parsed datetime inputs"));
18051807
const char *fmt = jv_string_value(b);
1806-
size_t alloced = strlen(fmt) + 100;
1807-
char *buf = alloca(alloced);
1808-
size_t n = strftime(buf, alloced, fmt, &tm);
1808+
size_t max_size = strlen(fmt) + 100;
1809+
char *buf = jv_mem_alloc(max_size);
1810+
size_t n = strftime(buf, max_size, fmt, &tm);
18091811
jv_free(b);
18101812
/* POSIX doesn't provide errno values for strftime() failures; weird */
1811-
if (n == 0 || n > alloced)
1813+
if ((n == 0 && *fmt) || n > max_size) {
1814+
free(buf);
18121815
return jv_invalid_with_msg(jv_string("strflocaltime/1: unknown system failure"));
1813-
return jv_string(buf);
1816+
}
1817+
jv ret = jv_string_sized(buf, n);
1818+
free(buf);
1819+
return ret;
18141820
}
18151821
#else
18161822
static jv f_strflocaltime(jq_state *jq, jv a, jv b) {
@@ -1912,6 +1918,8 @@ BINOPS
19121918
CFUNC(f_sort, "sort", 1),
19131919
CFUNC(f_sort_by_impl, "_sort_by_impl", 2),
19141920
CFUNC(f_group_by_impl, "_group_by_impl", 2),
1921+
CFUNC(f_unique, "unique", 1),
1922+
CFUNC(f_unique_by_impl, "_unique_by_impl", 2),
19151923
CFUNC(f_bsearch, "bsearch", 2),
19161924
CFUNC(f_min, "min", 1),
19171925
CFUNC(f_max, "max", 1),

src/builtin.jq

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ def map(f): [.[] | f];
44
def select(f): if f then . else empty end;
55
def sort_by(f): _sort_by_impl(map([f]));
66
def group_by(f): _group_by_impl(map([f]));
7-
def unique: group_by(.) | map(.[0]);
8-
def unique_by(f): group_by(f) | map(.[0]);
7+
def unique_by(f): _unique_by_impl(map([f]));
98
def max_by(f): _max_by_impl(map([f]));
109
def min_by(f): _min_by_impl(map([f]));
1110
def add(f): reduce f as $x (null; . + $x);

src/compile.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
#include <assert.h>
2-
#include <math.h>
32
#include <string.h>
43
#include <stdlib.h>
54
#include <unistd.h>
65
#include "compile.h"
76
#include "bytecode.h"
87
#include "locfile.h"
98
#include "jv_alloc.h"
10-
#include "linker.h"
119

1210
/*
1311
The intermediate representation for jq filters is as a sequence of
@@ -1374,7 +1372,7 @@ int block_compile(block b, struct bytecode** out, struct locfile* lf, jv args) {
13741372
bc->globals = jv_mem_alloc(sizeof(struct symbol_table));
13751373
int ncfunc = count_cfunctions(b);
13761374
bc->globals->ncfunctions = 0;
1377-
bc->globals->cfunctions = jv_mem_calloc(ncfunc, sizeof(struct cfunction));
1375+
bc->globals->cfunctions = jv_mem_calloc(ncfunc ? ncfunc : 1, sizeof(struct cfunction));
13781376
bc->globals->cfunc_names = jv_array();
13791377
bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null());
13801378
jv env = jv_invalid();

0 commit comments

Comments
 (0)