From: Willy Tarreau Date: Fri, 21 Jun 2013 21:16:39 +0000 (+0200) Subject: BUG/MEDIUM: prevent gcc from moving empty keywords lists into BSS X-Git-Tag: v1.5-dev20~343 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dc13c11c1e1e4888227a291e5eac7156e057b27a;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h index e89ffe0aec..3c3f0018f3 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 664ef5c659..845e1de1e9 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 0392355fc8..d677ab2a51 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 75b232baa4..2490061094 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 25f54416c2..e4c3f4342a 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 e0fd30ff70..58236ba433 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 1ee95251c6..ce8b4f2bed 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 ee3e6ebbf2..bc54e114a7 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 9068050a5e..8d9844011e 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 bfce6a265f..4357b0407f 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 e6720c9f19..b67f024268 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 753b45737d..fd18934e90 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 004f293c00..ec26522f69 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 160502c950..5d245cf999 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 },