From fc81a5bc69fc6670839a01d21663b6af357834cc Mon Sep 17 00:00:00 2001 From: Emanuele Torre Date: Mon, 11 Dec 2023 17:37:51 +0100 Subject: [PATCH] builtin.inc: fix build with -Woverlength-strings C99 only allows string literals with length up to 4095 characters. This patch introduces a gen_jq_builtins generator program that generates the jq_builtins array in builtin.c as an array literal instead of a string literal to make compilation not fail when building with -Woverlength-strings. Also add -Woverlength-strings to CFLAGS to verify that the fix works. Fixes # 1481 --- .gitignore | 3 + Makefile.am | 24 ++++++-- src/builtin.c | 25 -------- src/gen_jq_builtins.c | 132 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 30 deletions(-) create mode 100644 src/gen_jq_builtins.c diff --git a/.gitignore b/.gitignore index d1ffac3838..dbcd31fcb7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ jq !tests/modules/lib/jq/ jq.1 +# Generator programs +src/gen_jq_builtins + # Generated source src/builtin.inc src/config_opts.inc diff --git a/Makefile.am b/Makefile.am index 41c6f357be..76de295aff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,9 @@ LIBJQ_SRC = src/builtin.c src/bytecode.c src/compile.c src/execute.c \ ### C build options -AM_CFLAGS = -Wextra -Wall -Wno-unused-parameter -Wno-unused-function +AM_CFLAGS = -Wextra -Wall -Woverlength-strings + +AM_CFLAGS += -Wno-unused-parameter -Wno-unused-function if WIN32 AM_CFLAGS += -municode @@ -117,12 +119,17 @@ src/config_opts.inc: fi | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' -e 's/^/#define JQ_CONFIG /' > $@ src/main.c: src/version.h src/config_opts.inc -src/builtin.inc: $(srcdir)/src/builtin.jq - mkdir -p src - $(AM_V_GEN) sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $(srcdir)/src/builtin.jq > $@ +src/gen_jq_builtins: $(srcdir)/src/gen_jq_builtins.c + @mkdir -p src + $(AM_V_CC) $(COMPILE) -o $@ $< + +src/builtin.inc: src/gen_jq_builtins $(srcdir)/src/builtin.jq + @mkdir -p src + $(AM_V_GEN)src/gen_jq_builtins $(srcdir)/src/builtin.jq > $@ src/builtin.o: src/builtin.inc -CLEANFILES = src/version.h .remake-version-h src/builtin.inc src/config_opts.inc +CLEANFILES = src/version.h .remake-version-h src/config_opts.inc \ + src/gen_jq_builtins src/builtin.inc bin_PROGRAMS = jq jq_SOURCES = src/main.c src/version.h @@ -137,6 +144,13 @@ if ENABLE_ALL_STATIC jq_LDFLAGS += -all-static endif +bin_PROGRAMS += src/gen_jq_builtins +gen_jq_builtins_SOURCES = src/gen_jq_builtins.c + +if WIN32 +gen_jq_builtins_LIBADD = -lshlwapi +endif + ### Tests (make check) TESTS = tests/mantest tests/jqtest tests/shtest tests/utf8test tests/base64test diff --git a/src/builtin.c b/src/builtin.c index 2630fbd1d2..49da351cd7 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1798,33 +1798,8 @@ static block bind_bytecoded_builtins(block b) { static const char jq_builtins[] = /* Include jq-coded builtins */ #include "src/builtin.inc" - -/* Include unsupported math functions next */ -#define LIBM_DD(name) -#define LIBM_DDD(name) -#define LIBM_DDDD(name) -#define LIBM_DD_NO(name) "def " #name ": \"Error: " #name "/0 not found at build time\"|error;" -#define LIBM_DDD_NO(name) "def " #name "(a;b): \"Error: " #name "/2 not found at build time\"|error;" -#define LIBM_DDDD_NO(name) "def " #name "(a;b;c): \"Error: " #name "/3 not found at build time\"|error;" -#include "libm.h" -#ifndef HAVE_FREXP - "def frexp: \"Error: frexp/0 not found at build time\"|error;" -#endif -#ifndef HAVE_MODF - "def modf: \"Error: modf/0 not found at build time\"|error;" -#endif -#ifndef HAVE_LGAMMA_R - "def lgamma_r: \"Error: lgamma_r/0 not found at build time\"|error;" -#endif ; -#undef LIBM_DDDD_NO -#undef LIBM_DDD_NO -#undef LIBM_DD_NO -#undef LIBM_DDDD -#undef LIBM_DDD -#undef LIBM_DD - static block gen_builtin_list(block builtins) { jv list = jv_array_append(block_list_funcs(builtins, 1), jv_string("builtins/0")); return BLOCK(builtins, gen_function("builtins", gen_noop(), gen_const(list))); diff --git a/src/gen_jq_builtins.c b/src/gen_jq_builtins.c new file mode 100644 index 0000000000..886ca8271a --- /dev/null +++ b/src/gen_jq_builtins.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +#include "main-win32.h" +#include "math-macos.h" + +static uint_least8_t index = 0; + +static bool indentation(void) { + if (index == 0 && fputs(" ", stdout) == EOF) { + perror("fputs"); + return false; + } + return true; +} + +static bool separator(void) { + if (putchar(index < 10 ? ' ' : '\n') == EOF) { + perror("putchar"); + return false; + } + index = (index + 1) % 11; + return true; +} + +static bool gen_char(char const ch) { + if (!indentation()) + return false; + if (printf("%.4o,", (unsigned)ch) == EOF) + return false; + return separator(); +} + +bool gen_string(char const *const string) +{ + for (char const *ch = string; *ch; ++ch) { + if (!gen_char(*ch)) + return false; + } + return true; +} + +bool gen_file(FILE *const fp) { + for (int ch; (ch = getc(fp)) != EOF;) { + if (!gen_char(ch)) + return false; + } + if (ferror(fp)) { + perror("getc"); + return false; + } + return true; +} + +DEFINE_MAIN(int argc, char const *const argv[]) { + /* argv[1] must be the path to "src/builtin.jq" */ + if (argc != 2) { + static char const err[] = + "gen_builtin_inc: Wrong number of arguments.\n"; + if (fputs(err, stderr) == EOF) + perror("fputs"); + return EXIT_FAILURE; + } + + if (puts("{") == EOF) { + perror("puts"); + return EXIT_FAILURE; + } + + FILE *const builtin_jq = fopen(argv[1], "r"); + if (!builtin_jq) { + perror("fopen"); + return EXIT_FAILURE; + } + if (!gen_file(builtin_jq)) + return EXIT_FAILURE; + +#define GEN_STRING(string) \ + do { \ + if (!gen_string(string)) \ + return EXIT_FAILURE; \ + } while (0) + + /* Unsupported math functions */ +#define LIBM_DD(name) +#define LIBM_DDD(name) +#define LIBM_DDDD(name) +#define LIBM_DD_NO(name) \ + gen_string( \ + "def " #name ":" \ + "\"Error: " #name "/0 not found at build time\"|error;"); +#define LIBM_DDD_NO(name) \ + gen_string( \ + "def " #name "(a;b):" \ + "\"Error: " #name "/2 not found at build time\"|error;"); +#define LIBM_DDDD_NO(name) \ + gen_string("def " #name "(a;b;c):" \ + "\"Error: " #name "/3 not found at build time\"|error;"); +#include "libm.h" +#undef LIBM_DD +#undef LIBM_DDD +#undef LIBM_DDDD +#undef LIBM_DD_NO +#undef LIBM_DDD_NO +#undef LIBM_DDDD_NO + +#ifndef HAVE_FREXP + GEN_STRING( + "def frexp:" + "\"Error: frexp/0 not found at build time\"|error;"); +#endif +#ifndef HAVE_MODF + GEN_STRING( + "def modf:" + "\"Error: modf/0 not found at build time\"|error;"); +#endif +#ifndef HAVE_LGAMMA_R + GEN_STRING( + "def lgamma_r:" + "\"Error: lgamma_r/0 not found at build time\"|error;"); +#endif + +#undef GEN_STRING + + if (puts("'\\0',\n}") == EOF) { + perror("puts"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +}