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 e89ffe0..3c3f001 100644
--- a/include/common/mini-clist.h
+++ b/include/common/mini-clist.h
@@ -53,6 +53,12 @@
#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 664ef5c..845e1de 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -2010,7 +2010,7 @@
* 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 @@
/* 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 */ },
}};
diff --git a/src/backend.c b/src/backend.c
index 0392355..d677ab2 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1579,7 +1579,7 @@
/* 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 @@
/* 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 */ },
}};
diff --git a/src/compression.c b/src/compression.c
index 75b232b..2490061 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -635,12 +635,12 @@
}
/* 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 */ },
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 25f5441..e4c3f43 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -4439,7 +4439,7 @@
.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 e0fd30f..58236ba 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -256,7 +256,7 @@
/* 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 @@
/* 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 */ },
}};
diff --git a/src/listener.c b/src/listener.c
index 1ee9525..ce8b4f2 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -643,7 +643,7 @@
/* 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 @@
/* 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 */ },
}};
diff --git a/src/payload.c b/src/payload.c
index ee3e6eb..bc54e11 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -650,7 +650,7 @@
* 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 @@
/* 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 },
diff --git a/src/proto_http.c b/src/proto_http.c
index 9068050..8d98440 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -10106,7 +10106,7 @@
/* 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 @@
/* 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 },
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index bfce6a2..4357b04 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1731,7 +1731,7 @@
}
#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 @@
/* 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 @@
* 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 e6720c9..b67f024 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -859,7 +859,7 @@
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 753b457..fd18934 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -1073,7 +1073,7 @@
}
/* 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 },
diff --git a/src/session.c b/src/session.c
index 004f293..ec26522 100644
--- a/src/session.c
+++ b/src/session.c
@@ -3938,14 +3938,14 @@
/* 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, },
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 160502c..5d245cf 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -3080,7 +3080,7 @@
/* 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 @@
/* 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 },