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.
This commit is contained in:
Willy Tarreau 2013-06-21 23:16:39 +02:00
parent 8615c2af67
commit dc13c11c1e
14 changed files with 30 additions and 24 deletions

View File

@ -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))

View File

@ -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 <const> 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 */ },
}};

View File

@ -1579,7 +1579,7 @@ smp_fetch_srv_sess_rate(struct proxy *px, struct session *l4, void *l7, unsigned
/* Note: must not be declared <const> 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 <const> 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 */ },
}};

View File

@ -635,12 +635,12 @@ smp_fetch_res_comp_algo(struct proxy *px, struct session *l4, void *l7, unsigned
}
/* Note: must not be declared <const> 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 <const> 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 */ },

View File

@ -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 },
}};

View File

@ -256,7 +256,7 @@ smp_fetch_fe_conn(struct proxy *px, struct session *l4, void *l7, unsigned int o
/* Note: must not be declared <const> 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 <const> 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 */ },
}};

View File

@ -643,7 +643,7 @@ static int bind_parse_nice(char **args, int cur_arg, struct proxy *px, struct bi
/* Note: must not be declared <const> 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 <const> 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 */ },
}};

View File

@ -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 <const> 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 },

View File

@ -10106,7 +10106,7 @@ static int val_hdr(struct arg *arg, char **err_msg)
/* Note: must not be declared <const> 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 <const> 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 },

View File

@ -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 <const> 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 },

View File

@ -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 },

View File

@ -1073,7 +1073,7 @@ static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp)
}
/* Note: must not be declared <const> 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 },

View File

@ -3938,14 +3938,14 @@ smp_fetch_table_avl(struct proxy *px, struct session *l4, void *l7, unsigned int
/* Note: must not be declared <const> 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 <const> 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, },

View File

@ -3080,7 +3080,7 @@ static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct
/* Note: must not be declared <const> 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 <const> 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 },