From dc13c11c1e1e4888227a291e5eac7156e057b27a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 21 Jun 2013 23:16:39 +0200 Subject: [PATCH] BUG/MEDIUM: prevent gcc from moving empty keywords lists into BSS Benoit Dolez reported a failure to start haproxy 1.5-dev19. The process would immediately report an internal error with missing fetches from some crap instead of ACL names. The cause is that some versions of gcc seem to trim static structs containing a variable array when moving them to BSS, and only keep the fixed size, which is just a list head for all ACL and sample fetch keywords. This was confirmed at least with gcc 3.4.6. And we can't move these structs to const because they contain a list element which is needed to link all of them together during the parsing. The bug indeed appeared with 1.5-dev19 because it's the first one to have some empty ACL keyword lists. One solution is to impose -fno-zero-initialized-in-bss to everyone but this is not really nice. Another solution consists in ensuring the struct is never empty so that it does not move there. The easy solution consists in having a non-null list head since it's not yet initialized. A new "ILH" list head type was thus created for this purpose : create an Initialized List Head so that gcc cannot move the struct to BSS. This fixes the issue for this version of gcc and does not create any burden for the declarations. --- include/common/mini-clist.h | 6 ++++++ src/acl.c | 4 ++-- src/backend.c | 4 ++-- src/compression.c | 4 ++-- src/dumpstats.c | 2 +- src/frontend.c | 4 ++-- src/listener.c | 4 ++-- src/payload.c | 4 ++-- src/proto_http.c | 4 ++-- src/proto_tcp.c | 6 +++--- src/proxy.c | 2 +- src/sample.c | 2 +- src/session.c | 4 ++-- src/ssl_sock.c | 4 ++-- 14 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h index e89ffe0ae..3c3f0018f 100644 --- a/include/common/mini-clist.h +++ b/include/common/mini-clist.h @@ -53,6 +53,12 @@ struct cond_wordlist { #undef LIST_INIT #undef LIST_NEXT +/* ILH = Initialized List Head : used to prevent gcc from moving an empty + * list to BSS. Some older version tend to trim all the array and cause + * corruption. + */ +#define ILH { .n = (struct list *)1, .p = (struct list *)2 } + #define LIST_HEAD(a) ((void *)(&(a))) #define LIST_INIT(l) ((l)->n = (l)->p = (l)) diff --git a/src/acl.c b/src/acl.c index 664ef5c65..845e1de1e 100644 --- a/src/acl.c +++ b/src/acl.c @@ -2010,7 +2010,7 @@ smp_fetch_env(struct proxy *px, struct session *s, void *l7, unsigned int opt, * common denominator, the type that can be casted into all other ones. For * instance IPv4/IPv6 must be declared IPv4. */ -static struct sample_fetch_kw_list smp_kws = {{ },{ +static struct sample_fetch_kw_list smp_kws = {ILH, { { "always_false", smp_fetch_false, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN }, { "always_true", smp_fetch_true, 0, NULL, SMP_T_BOOL, SMP_USE_INTRN }, { "env", smp_fetch_env, ARG1(1,STR), NULL, SMP_T_CSTR, SMP_USE_INTRN }, @@ -2021,7 +2021,7 @@ static struct sample_fetch_kw_list smp_kws = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; diff --git a/src/backend.c b/src/backend.c index 0392355fc..d677ab2a5 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1579,7 +1579,7 @@ smp_fetch_srv_sess_rate(struct proxy *px, struct session *l4, void *l7, unsigned /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct sample_fetch_kw_list smp_kws = {{ },{ +static struct sample_fetch_kw_list smp_kws = {ILH, { { "avg_queue", smp_fetch_avg_queue_size, ARG1(1,BE), NULL, SMP_T_UINT, SMP_USE_INTRN, }, { "be_conn", smp_fetch_be_conn, ARG1(1,BE), NULL, SMP_T_UINT, SMP_USE_INTRN, }, { "be_id", smp_fetch_be_id, 0, NULL, SMP_T_UINT, SMP_USE_BKEND, }, @@ -1598,7 +1598,7 @@ static struct sample_fetch_kw_list smp_kws = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; diff --git a/src/compression.c b/src/compression.c index 75b232baa..249006109 100644 --- a/src/compression.c +++ b/src/compression.c @@ -635,12 +635,12 @@ smp_fetch_res_comp_algo(struct proxy *px, struct session *l4, void *l7, unsigned } /* Note: must not be declared as its list will be overwritten */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; /* Note: must not be declared as its list will be overwritten */ -static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{ +static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { { "res.comp", smp_fetch_res_comp, 0, NULL, SMP_T_BOOL, SMP_USE_HRSHP }, { "res.comp_algo", smp_fetch_res_comp_algo, 0, NULL, SMP_T_STR, SMP_USE_HRSHP }, { /* END */ }, diff --git a/src/dumpstats.c b/src/dumpstats.c index 25f54416c..e4c3f4342 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -4439,7 +4439,7 @@ static struct si_applet cli_applet = { .release = cli_release_handler, }; -static struct cfg_kw_list cfg_kws = {{ },{ +static struct cfg_kw_list cfg_kws = {ILH, { { CFG_GLOBAL, "stats", stats_parse_global }, { 0, NULL, NULL }, }}; diff --git a/src/frontend.c b/src/frontend.c index e0fd30ff7..58236ba43 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -256,7 +256,7 @@ smp_fetch_fe_conn(struct proxy *px, struct session *l4, void *l7, unsigned int o /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct sample_fetch_kw_list smp_kws = {{ },{ +static struct sample_fetch_kw_list smp_kws = {ILH, { { "fe_conn", smp_fetch_fe_conn, ARG1(1,FE), NULL, SMP_T_UINT, SMP_USE_INTRN, }, { "fe_id", smp_fetch_fe_id, 0, NULL, SMP_T_UINT, SMP_USE_FTEND, }, { "fe_sess_rate", smp_fetch_fe_sess_rate, ARG1(1,FE), NULL, SMP_T_UINT, SMP_USE_INTRN, }, @@ -267,7 +267,7 @@ static struct sample_fetch_kw_list smp_kws = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; diff --git a/src/listener.c b/src/listener.c index 1ee95251c..ce8b4f2be 100644 --- a/src/listener.c +++ b/src/listener.c @@ -643,7 +643,7 @@ static int bind_parse_nice(char **args, int cur_arg, struct proxy *px, struct bi /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct sample_fetch_kw_list smp_kws = {{ },{ +static struct sample_fetch_kw_list smp_kws = {ILH, { { "dst_conn", smp_fetch_dconn, 0, NULL, SMP_T_UINT, SMP_USE_FTEND, }, { "so_id", smp_fetch_so_id, 0, NULL, SMP_T_UINT, SMP_USE_FTEND, }, { /* END */ }, @@ -652,7 +652,7 @@ static struct sample_fetch_kw_list smp_kws = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; diff --git a/src/payload.c b/src/payload.c index ee3e6ebbf..bc54e114a 100644 --- a/src/payload.c +++ b/src/payload.c @@ -650,7 +650,7 @@ static int val_payload_lv(struct arg *arg, char **err_msg) * common denominator, the type that can be casted into all other ones. For * instance IPv4/IPv6 must be declared IPv4. */ -static struct sample_fetch_kw_list smp_kws = {{ },{ +static struct sample_fetch_kw_list smp_kws = {ILH, { { "payload", smp_fetch_payload, ARG2(2,UINT,UINT), val_payload, SMP_T_CBIN, SMP_USE_L6REQ|SMP_USE_L6RES }, { "payload_lv", smp_fetch_payload_lv, ARG3(2,UINT,UINT,SINT), val_payload_lv, SMP_T_CBIN, SMP_USE_L6REQ|SMP_USE_L6RES }, { "rdp_cookie", smp_fetch_rdp_cookie, ARG1(0,STR), NULL, SMP_T_CSTR, SMP_USE_L6REQ }, @@ -680,7 +680,7 @@ static struct sample_fetch_kw_list smp_kws = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { "payload", "req.payload", acl_parse_str, acl_match_str }, { "payload_lv", "req.payload_lv", acl_parse_str, acl_match_str }, { "req_rdp_cookie", "req.rdp_cookie", acl_parse_str, acl_match_str }, diff --git a/src/proto_http.c b/src/proto_http.c index 9068050a5..8d9844011 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -10106,7 +10106,7 @@ static int val_hdr(struct arg *arg, char **err_msg) /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { "base", "base", acl_parse_str, acl_match_str }, { "base_beg", "base", acl_parse_str, acl_match_beg }, { "base_dir", "base", acl_parse_str, acl_match_dir }, @@ -10193,7 +10193,7 @@ static struct acl_kw_list acl_kws = {{ },{ /* All supported pattern keywords must be declared here. */ /************************************************************************/ /* Note: must not be declared as its list will be overwritten */ -static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{ +static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { { "base", smp_fetch_base, 0, NULL, SMP_T_CSTR, SMP_USE_HRQHV }, { "base32", smp_fetch_base32, 0, NULL, SMP_T_UINT, SMP_USE_HRQHV }, { "base32+src", smp_fetch_base32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV }, diff --git a/src/proto_tcp.c b/src/proto_tcp.c index bfce6a265..4357b0407 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -1731,7 +1731,7 @@ static int bind_parse_interface(char **args, int cur_arg, struct proxy *px, stru } #endif -static struct cfg_kw_list cfg_kws = {{ },{ +static struct cfg_kw_list cfg_kws = {ILH, { { CFG_LISTEN, "tcp-request", tcp_parse_tcp_req }, { CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep }, { 0, NULL, NULL }, @@ -1741,7 +1741,7 @@ static struct cfg_kw_list cfg_kws = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; @@ -1751,7 +1751,7 @@ static struct acl_kw_list acl_kws = {{ },{ * common denominator, the type that can be casted into all other ones. For * instance v4/v6 must be declared v4. */ -static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{ +static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_UINT, SMP_USE_L4CLI }, { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI }, diff --git a/src/proxy.c b/src/proxy.c index e6720c9f1..b67f02426 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -859,7 +859,7 @@ int session_set_backend(struct session *s, struct proxy *be) return 1; } -static struct cfg_kw_list cfg_kws = {{ },{ +static struct cfg_kw_list cfg_kws = {ILH, { { CFG_LISTEN, "timeout", proxy_parse_timeout }, { CFG_LISTEN, "clitimeout", proxy_parse_timeout }, { CFG_LISTEN, "contimeout", proxy_parse_timeout }, diff --git a/src/sample.c b/src/sample.c index 753b45737..fd18934e9 100644 --- a/src/sample.c +++ b/src/sample.c @@ -1073,7 +1073,7 @@ static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp) } /* Note: must not be declared as its list will be overwritten */ -static struct sample_conv_kw_list sample_conv_kws = {{ },{ +static struct sample_conv_kw_list sample_conv_kws = {ILH, { { "upper", sample_conv_str2upper, 0, NULL, SMP_T_STR, SMP_T_STR }, { "lower", sample_conv_str2lower, 0, NULL, SMP_T_STR, SMP_T_STR }, { "ipmask", sample_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 }, diff --git a/src/session.c b/src/session.c index 004f293c0..ec26522f6 100644 --- a/src/session.c +++ b/src/session.c @@ -3938,14 +3938,14 @@ smp_fetch_table_avl(struct proxy *px, struct session *l4, void *l7, unsigned int /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { /* END */ }, }}; /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct sample_fetch_kw_list smp_fetch_keywords = {{ },{ +static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, { { "sc0_bytes_in_rate", smp_fetch_sc0_bytes_in_rate, 0, NULL, SMP_T_UINT, SMP_USE_INTRN, }, { "sc0_bytes_out_rate", smp_fetch_sc0_bytes_out_rate, 0, NULL, SMP_T_UINT, SMP_USE_INTRN, }, { "sc0_clr_gpc0", smp_fetch_sc0_clr_gpc0, 0, NULL, SMP_T_UINT, SMP_USE_INTRN, }, diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 160502c95..5d245cf99 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -3080,7 +3080,7 @@ static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{ +static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { { "ssl_c_ca_err", smp_fetch_ssl_c_ca_err, 0, NULL, SMP_T_UINT, SMP_USE_L5CLI }, { "ssl_c_ca_err_depth", smp_fetch_ssl_c_ca_err_depth, 0, NULL, SMP_T_UINT, SMP_USE_L5CLI }, { "ssl_c_err", smp_fetch_ssl_c_err, 0, NULL, SMP_T_UINT, SMP_USE_L5CLI }, @@ -3124,7 +3124,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{ /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ -static struct acl_kw_list acl_kws = {{ },{ +static struct acl_kw_list acl_kws = {ILH, { { "ssl_c_i_dn", NULL, acl_parse_str, acl_match_str }, { "ssl_c_key_alg", NULL, acl_parse_str, acl_match_str }, { "ssl_c_notafter", NULL, acl_parse_str, acl_match_str }, -- 2.47.3