Skip to content

Commit

Permalink
builtin.inc: fix build with -Woverlength-strings
Browse files Browse the repository at this point in the history
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
  • Loading branch information
emanuele6 committed Dec 11, 2023
1 parent ea42d01 commit d052f52
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 30 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 19 additions & 5 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
25 changes: 0 additions & 25 deletions src/builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down
131 changes: 131 additions & 0 deletions src/gen_jq_builtins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.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;
}

int 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;
}

0 comments on commit d052f52

Please sign in to comment.