commit
105f0d4793
@ -0,0 +1 @@
|
||||
SOURCES/glibc-2.28.tar.xz
|
@ -0,0 +1 @@
|
||||
ccb5dc9e51a9884df8488f86982439d47b283b2a SOURCES/glibc-2.28.tar.xz
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,496 @@
|
||||
# This file names the currently supported and somewhat tested locales.
|
||||
# If you have any additions please file a glibc bug report.
|
||||
SUPPORTED-LOCALES=\
|
||||
C.UTF-8/UTF-8 \
|
||||
aa_DJ.UTF-8/UTF-8 \
|
||||
aa_DJ/ISO-8859-1 \
|
||||
aa_ER/UTF-8 \
|
||||
aa_ER@saaho/UTF-8 \
|
||||
aa_ET/UTF-8 \
|
||||
af_ZA.UTF-8/UTF-8 \
|
||||
af_ZA/ISO-8859-1 \
|
||||
agr_PE/UTF-8 \
|
||||
ak_GH/UTF-8 \
|
||||
am_ET/UTF-8 \
|
||||
an_ES.UTF-8/UTF-8 \
|
||||
an_ES/ISO-8859-15 \
|
||||
anp_IN/UTF-8 \
|
||||
ar_AE.UTF-8/UTF-8 \
|
||||
ar_AE/ISO-8859-6 \
|
||||
ar_BH.UTF-8/UTF-8 \
|
||||
ar_BH/ISO-8859-6 \
|
||||
ar_DZ.UTF-8/UTF-8 \
|
||||
ar_DZ/ISO-8859-6 \
|
||||
ar_EG.UTF-8/UTF-8 \
|
||||
ar_EG/ISO-8859-6 \
|
||||
ar_IN/UTF-8 \
|
||||
ar_IQ.UTF-8/UTF-8 \
|
||||
ar_IQ/ISO-8859-6 \
|
||||
ar_JO.UTF-8/UTF-8 \
|
||||
ar_JO/ISO-8859-6 \
|
||||
ar_KW.UTF-8/UTF-8 \
|
||||
ar_KW/ISO-8859-6 \
|
||||
ar_LB.UTF-8/UTF-8 \
|
||||
ar_LB/ISO-8859-6 \
|
||||
ar_LY.UTF-8/UTF-8 \
|
||||
ar_LY/ISO-8859-6 \
|
||||
ar_MA.UTF-8/UTF-8 \
|
||||
ar_MA/ISO-8859-6 \
|
||||
ar_OM.UTF-8/UTF-8 \
|
||||
ar_OM/ISO-8859-6 \
|
||||
ar_QA.UTF-8/UTF-8 \
|
||||
ar_QA/ISO-8859-6 \
|
||||
ar_SA.UTF-8/UTF-8 \
|
||||
ar_SA/ISO-8859-6 \
|
||||
ar_SD.UTF-8/UTF-8 \
|
||||
ar_SD/ISO-8859-6 \
|
||||
ar_SS/UTF-8 \
|
||||
ar_SY.UTF-8/UTF-8 \
|
||||
ar_SY/ISO-8859-6 \
|
||||
ar_TN.UTF-8/UTF-8 \
|
||||
ar_TN/ISO-8859-6 \
|
||||
ar_YE.UTF-8/UTF-8 \
|
||||
ar_YE/ISO-8859-6 \
|
||||
ayc_PE/UTF-8 \
|
||||
az_AZ/UTF-8 \
|
||||
az_IR/UTF-8 \
|
||||
as_IN/UTF-8 \
|
||||
ast_ES.UTF-8/UTF-8 \
|
||||
ast_ES/ISO-8859-15 \
|
||||
be_BY.UTF-8/UTF-8 \
|
||||
be_BY/CP1251 \
|
||||
be_BY@latin/UTF-8 \
|
||||
bem_ZM/UTF-8 \
|
||||
ber_DZ/UTF-8 \
|
||||
ber_MA/UTF-8 \
|
||||
bg_BG.UTF-8/UTF-8 \
|
||||
bg_BG/CP1251 \
|
||||
bhb_IN.UTF-8/UTF-8 \
|
||||
bho_IN/UTF-8 \
|
||||
bho_NP/UTF-8 \
|
||||
bi_VU/UTF-8 \
|
||||
bn_BD/UTF-8 \
|
||||
bn_IN/UTF-8 \
|
||||
bo_CN/UTF-8 \
|
||||
bo_IN/UTF-8 \
|
||||
br_FR.UTF-8/UTF-8 \
|
||||
br_FR/ISO-8859-1 \
|
||||
br_FR@euro/ISO-8859-15 \
|
||||
brx_IN/UTF-8 \
|
||||
bs_BA.UTF-8/UTF-8 \
|
||||
bs_BA/ISO-8859-2 \
|
||||
byn_ER/UTF-8 \
|
||||
ca_AD.UTF-8/UTF-8 \
|
||||
ca_AD/ISO-8859-15 \
|
||||
ca_ES.UTF-8/UTF-8 \
|
||||
ca_ES/ISO-8859-1 \
|
||||
ca_ES@euro/ISO-8859-15 \
|
||||
ca_ES@valencia/UTF-8 \
|
||||
ca_FR.UTF-8/UTF-8 \
|
||||
ca_FR/ISO-8859-15 \
|
||||
ca_IT.UTF-8/UTF-8 \
|
||||
ca_IT/ISO-8859-15 \
|
||||
ce_RU/UTF-8 \
|
||||
chr_US/UTF-8 \
|
||||
cmn_TW/UTF-8 \
|
||||
crh_UA/UTF-8 \
|
||||
cs_CZ.UTF-8/UTF-8 \
|
||||
cs_CZ/ISO-8859-2 \
|
||||
csb_PL/UTF-8 \
|
||||
cv_RU/UTF-8 \
|
||||
cy_GB.UTF-8/UTF-8 \
|
||||
cy_GB/ISO-8859-14 \
|
||||
da_DK.UTF-8/UTF-8 \
|
||||
da_DK/ISO-8859-1 \
|
||||
da_DK.ISO-8859-15/ISO-8859-15 \
|
||||
de_AT.UTF-8/UTF-8 \
|
||||
de_AT/ISO-8859-1 \
|
||||
de_AT@euro/ISO-8859-15 \
|
||||
de_BE.UTF-8/UTF-8 \
|
||||
de_BE/ISO-8859-1 \
|
||||
de_BE@euro/ISO-8859-15 \
|
||||
de_CH.UTF-8/UTF-8 \
|
||||
de_CH/ISO-8859-1 \
|
||||
de_DE.UTF-8/UTF-8 \
|
||||
de_DE/ISO-8859-1 \
|
||||
de_DE@euro/ISO-8859-15 \
|
||||
de_IT.UTF-8/UTF-8 \
|
||||
de_IT/ISO-8859-1 \
|
||||
de_LI.UTF-8/UTF-8 \
|
||||
de_LU.UTF-8/UTF-8 \
|
||||
de_LU/ISO-8859-1 \
|
||||
de_LU@euro/ISO-8859-15 \
|
||||
doi_IN/UTF-8 \
|
||||
dsb_DE/UTF-8 \
|
||||
dv_MV/UTF-8 \
|
||||
dz_BT/UTF-8 \
|
||||
el_GR.UTF-8/UTF-8 \
|
||||
el_GR/ISO-8859-7 \
|
||||
el_GR@euro/ISO-8859-7 \
|
||||
el_CY.UTF-8/UTF-8 \
|
||||
el_CY/ISO-8859-7 \
|
||||
en_AG/UTF-8 \
|
||||
en_AU.UTF-8/UTF-8 \
|
||||
en_AU/ISO-8859-1 \
|
||||
en_BW.UTF-8/UTF-8 \
|
||||
en_BW/ISO-8859-1 \
|
||||
en_CA.UTF-8/UTF-8 \
|
||||
en_CA/ISO-8859-1 \
|
||||
en_DK.UTF-8/UTF-8 \
|
||||
en_DK/ISO-8859-1 \
|
||||
en_GB.UTF-8/UTF-8 \
|
||||
en_GB/ISO-8859-1 \
|
||||
en_GB.ISO-8859-15/ISO-8859-15 \
|
||||
en_HK.UTF-8/UTF-8 \
|
||||
en_HK/ISO-8859-1 \
|
||||
en_IE.UTF-8/UTF-8 \
|
||||
en_IE/ISO-8859-1 \
|
||||
en_IE@euro/ISO-8859-15 \
|
||||
en_IL/UTF-8 \
|
||||
en_IN/UTF-8 \
|
||||
en_NG/UTF-8 \
|
||||
en_NZ.UTF-8/UTF-8 \
|
||||
en_NZ/ISO-8859-1 \
|
||||
en_PH.UTF-8/UTF-8 \
|
||||
en_PH/ISO-8859-1 \
|
||||
en_SC.UTF-8/UTF-8 \
|
||||
en_SG.UTF-8/UTF-8 \
|
||||
en_SG/ISO-8859-1 \
|
||||
en_US.UTF-8/UTF-8 \
|
||||
en_US/ISO-8859-1 \
|
||||
en_US.ISO-8859-15/ISO-8859-15 \
|
||||
en_US@ampm/UTF-8 \
|
||||
en_US.UTF-8@ampm/UTF-8 \
|
||||
en_ZA.UTF-8/UTF-8 \
|
||||
en_ZA/ISO-8859-1 \
|
||||
en_ZM/UTF-8 \
|
||||
en_ZW.UTF-8/UTF-8 \
|
||||
en_ZW/ISO-8859-1 \
|
||||
eo/UTF-8 \
|
||||
es_AR.UTF-8/UTF-8 \
|
||||
es_AR/ISO-8859-1 \
|
||||
es_BO.UTF-8/UTF-8 \
|
||||
es_BO/ISO-8859-1 \
|
||||
es_CL.UTF-8/UTF-8 \
|
||||
es_CL/ISO-8859-1 \
|
||||
es_CO.UTF-8/UTF-8 \
|
||||
es_CO/ISO-8859-1 \
|
||||
es_CR.UTF-8/UTF-8 \
|
||||
es_CR/ISO-8859-1 \
|
||||
es_CU/UTF-8 \
|
||||
es_DO.UTF-8/UTF-8 \
|
||||
es_DO/ISO-8859-1 \
|
||||
es_EC.UTF-8/UTF-8 \
|
||||
es_EC/ISO-8859-1 \
|
||||
es_ES.UTF-8/UTF-8 \
|
||||
es_ES/ISO-8859-1 \
|
||||
es_ES@euro/ISO-8859-15 \
|
||||
es_GT.UTF-8/UTF-8 \
|
||||
es_GT/ISO-8859-1 \
|
||||
es_HN.UTF-8/UTF-8 \
|
||||
es_HN/ISO-8859-1 \
|
||||
es_MX.UTF-8/UTF-8 \
|
||||
es_MX/ISO-8859-1 \
|
||||
es_NI.UTF-8/UTF-8 \
|
||||
es_NI/ISO-8859-1 \
|
||||
es_PA.UTF-8/UTF-8 \
|
||||
es_PA/ISO-8859-1 \
|
||||
es_PE.UTF-8/UTF-8 \
|
||||
es_PE/ISO-8859-1 \
|
||||
es_PR.UTF-8/UTF-8 \
|
||||
es_PR/ISO-8859-1 \
|
||||
es_PY.UTF-8/UTF-8 \
|
||||
es_PY/ISO-8859-1 \
|
||||
es_SV.UTF-8/UTF-8 \
|
||||
es_SV/ISO-8859-1 \
|
||||
es_US.UTF-8/UTF-8 \
|
||||
es_US/ISO-8859-1 \
|
||||
es_UY.UTF-8/UTF-8 \
|
||||
es_UY/ISO-8859-1 \
|
||||
es_VE.UTF-8/UTF-8 \
|
||||
es_VE/ISO-8859-1 \
|
||||
et_EE.UTF-8/UTF-8 \
|
||||
et_EE/ISO-8859-1 \
|
||||
et_EE.ISO-8859-15/ISO-8859-15 \
|
||||
eu_ES.UTF-8/UTF-8 \
|
||||
eu_ES/ISO-8859-1 \
|
||||
eu_ES@euro/ISO-8859-15 \
|
||||
fa_IR/UTF-8 \
|
||||
ff_SN/UTF-8 \
|
||||
fi_FI.UTF-8/UTF-8 \
|
||||
fi_FI/ISO-8859-1 \
|
||||
fi_FI@euro/ISO-8859-15 \
|
||||
fil_PH/UTF-8 \
|
||||
fo_FO.UTF-8/UTF-8 \
|
||||
fo_FO/ISO-8859-1 \
|
||||
fr_BE.UTF-8/UTF-8 \
|
||||
fr_BE/ISO-8859-1 \
|
||||
fr_BE@euro/ISO-8859-15 \
|
||||
fr_CA.UTF-8/UTF-8 \
|
||||
fr_CA/ISO-8859-1 \
|
||||
fr_CH.UTF-8/UTF-8 \
|
||||
fr_CH/ISO-8859-1 \
|
||||
fr_FR.UTF-8/UTF-8 \
|
||||
fr_FR/ISO-8859-1 \
|
||||
fr_FR@euro/ISO-8859-15 \
|
||||
fr_LU.UTF-8/UTF-8 \
|
||||
fr_LU/ISO-8859-1 \
|
||||
fr_LU@euro/ISO-8859-15 \
|
||||
fur_IT/UTF-8 \
|
||||
fy_NL/UTF-8 \
|
||||
fy_DE/UTF-8 \
|
||||
ga_IE.UTF-8/UTF-8 \
|
||||
ga_IE/ISO-8859-1 \
|
||||
ga_IE@euro/ISO-8859-15 \
|
||||
gd_GB.UTF-8/UTF-8 \
|
||||
gd_GB/ISO-8859-15 \
|
||||
gez_ER/UTF-8 \
|
||||
gez_ER@abegede/UTF-8 \
|
||||
gez_ET/UTF-8 \
|
||||
gez_ET@abegede/UTF-8 \
|
||||
gl_ES.UTF-8/UTF-8 \
|
||||
gl_ES/ISO-8859-1 \
|
||||
gl_ES@euro/ISO-8859-15 \
|
||||
gu_IN/UTF-8 \
|
||||
gv_GB.UTF-8/UTF-8 \
|
||||
gv_GB/ISO-8859-1 \
|
||||
ha_NG/UTF-8 \
|
||||
hak_TW/UTF-8 \
|
||||
he_IL.UTF-8/UTF-8 \
|
||||
he_IL/ISO-8859-8 \
|
||||
hi_IN/UTF-8 \
|
||||
hif_FJ/UTF-8 \
|
||||
hne_IN/UTF-8 \
|
||||
hr_HR.UTF-8/UTF-8 \
|
||||
hr_HR/ISO-8859-2 \
|
||||
hsb_DE/ISO-8859-2 \
|
||||
hsb_DE.UTF-8/UTF-8 \
|
||||
ht_HT/UTF-8 \
|
||||
hu_HU.UTF-8/UTF-8 \
|
||||
hu_HU/ISO-8859-2 \
|
||||
hy_AM/UTF-8 \
|
||||
hy_AM.ARMSCII-8/ARMSCII-8 \
|
||||
ia_FR/UTF-8 \
|
||||
id_ID.UTF-8/UTF-8 \
|
||||
id_ID/ISO-8859-1 \
|
||||
ig_NG/UTF-8 \
|
||||
ik_CA/UTF-8 \
|
||||
is_IS.UTF-8/UTF-8 \
|
||||
is_IS/ISO-8859-1 \
|
||||
it_CH.UTF-8/UTF-8 \
|
||||
it_CH/ISO-8859-1 \
|
||||
it_IT.UTF-8/UTF-8 \
|
||||
it_IT/ISO-8859-1 \
|
||||
it_IT@euro/ISO-8859-15 \
|
||||
iu_CA/UTF-8 \
|
||||
ja_JP.EUC-JP/EUC-JP \
|
||||
ja_JP.UTF-8/UTF-8 \
|
||||
ka_GE.UTF-8/UTF-8 \
|
||||
ka_GE/GEORGIAN-PS \
|
||||
kab_DZ/UTF-8 \
|
||||
kk_KZ.UTF-8/UTF-8 \
|
||||
kk_KZ/PT154 \
|
||||
kl_GL.UTF-8/UTF-8 \
|
||||
kl_GL/ISO-8859-1 \
|
||||
km_KH/UTF-8 \
|
||||
kn_IN/UTF-8 \
|
||||
ko_KR.EUC-KR/EUC-KR \
|
||||
ko_KR.UTF-8/UTF-8 \
|
||||
kok_IN/UTF-8 \
|
||||
ks_IN/UTF-8 \
|
||||
ks_IN@devanagari/UTF-8 \
|
||||
ku_TR.UTF-8/UTF-8 \
|
||||
ku_TR/ISO-8859-9 \
|
||||
kw_GB.UTF-8/UTF-8 \
|
||||
kw_GB/ISO-8859-1 \
|
||||
ky_KG/UTF-8 \
|
||||
lb_LU/UTF-8 \
|
||||
lg_UG.UTF-8/UTF-8 \
|
||||
lg_UG/ISO-8859-10 \
|
||||
li_BE/UTF-8 \
|
||||
li_NL/UTF-8 \
|
||||
lij_IT/UTF-8 \
|
||||
ln_CD/UTF-8 \
|
||||
lo_LA/UTF-8 \
|
||||
lt_LT.UTF-8/UTF-8 \
|
||||
lt_LT/ISO-8859-13 \
|
||||
lv_LV.UTF-8/UTF-8 \
|
||||
lv_LV/ISO-8859-13 \
|
||||
lzh_TW/UTF-8 \
|
||||
mag_IN/UTF-8 \
|
||||
mai_IN/UTF-8 \
|
||||
mai_NP/UTF-8 \
|
||||
mfe_MU/UTF-8 \
|
||||
mg_MG.UTF-8/UTF-8 \
|
||||
mg_MG/ISO-8859-15 \
|
||||
mhr_RU/UTF-8 \
|
||||
mi_NZ.UTF-8/UTF-8 \
|
||||
mi_NZ/ISO-8859-13 \
|
||||
miq_NI/UTF-8 \
|
||||
mjw_IN/UTF-8 \
|
||||
mk_MK.UTF-8/UTF-8 \
|
||||
mk_MK/ISO-8859-5 \
|
||||
ml_IN/UTF-8 \
|
||||
mn_MN/UTF-8 \
|
||||
mni_IN/UTF-8 \
|
||||
mr_IN/UTF-8 \
|
||||
ms_MY.UTF-8/UTF-8 \
|
||||
ms_MY/ISO-8859-1 \
|
||||
mt_MT.UTF-8/UTF-8 \
|
||||
mt_MT/ISO-8859-3 \
|
||||
my_MM/UTF-8 \
|
||||
nan_TW/UTF-8 \
|
||||
nan_TW@latin/UTF-8 \
|
||||
nb_NO.UTF-8/UTF-8 \
|
||||
nb_NO/ISO-8859-1 \
|
||||
nds_DE/UTF-8 \
|
||||
nds_NL/UTF-8 \
|
||||
ne_NP/UTF-8 \
|
||||
nhn_MX/UTF-8 \
|
||||
niu_NU/UTF-8 \
|
||||
niu_NZ/UTF-8 \
|
||||
nl_AW/UTF-8 \
|
||||
nl_BE.UTF-8/UTF-8 \
|
||||
nl_BE/ISO-8859-1 \
|
||||
nl_BE@euro/ISO-8859-15 \
|
||||
nl_NL.UTF-8/UTF-8 \
|
||||
nl_NL/ISO-8859-1 \
|
||||
nl_NL@euro/ISO-8859-15 \
|
||||
nn_NO.UTF-8/UTF-8 \
|
||||
nn_NO/ISO-8859-1 \
|
||||
nr_ZA/UTF-8 \
|
||||
nso_ZA/UTF-8 \
|
||||
oc_FR.UTF-8/UTF-8 \
|
||||
oc_FR/ISO-8859-1 \
|
||||
om_ET/UTF-8 \
|
||||
om_KE.UTF-8/UTF-8 \
|
||||
om_KE/ISO-8859-1 \
|
||||
or_IN/UTF-8 \
|
||||
os_RU/UTF-8 \
|
||||
pa_IN/UTF-8 \
|
||||
pa_PK/UTF-8 \
|
||||
pap_AW/UTF-8 \
|
||||
pap_CW/UTF-8 \
|
||||
pl_PL.UTF-8/UTF-8 \
|
||||
pl_PL/ISO-8859-2 \
|
||||
ps_AF/UTF-8 \
|
||||
pt_BR.UTF-8/UTF-8 \
|
||||
pt_BR/ISO-8859-1 \
|
||||
pt_PT.UTF-8/UTF-8 \
|
||||
pt_PT/ISO-8859-1 \
|
||||
pt_PT@euro/ISO-8859-15 \
|
||||
quz_PE/UTF-8 \
|
||||
raj_IN/UTF-8 \
|
||||
ro_RO.UTF-8/UTF-8 \
|
||||
ro_RO/ISO-8859-2 \
|
||||
ru_RU.KOI8-R/KOI8-R \
|
||||
ru_RU.UTF-8/UTF-8 \
|
||||
ru_RU/ISO-8859-5 \
|
||||
ru_UA.UTF-8/UTF-8 \
|
||||
ru_UA/KOI8-U \
|
||||
rw_RW/UTF-8 \
|
||||
sa_IN/UTF-8 \
|
||||
sah_RU/UTF-8 \
|
||||
sat_IN/UTF-8 \
|
||||
sc_IT/UTF-8 \
|
||||
sd_IN/UTF-8 \
|
||||
sd_IN@devanagari/UTF-8 \
|
||||
se_NO/UTF-8 \
|
||||
sgs_LT/UTF-8 \
|
||||
shn_MM/UTF-8 \
|
||||
shs_CA/UTF-8 \
|
||||
si_LK/UTF-8 \
|
||||
sid_ET/UTF-8 \
|
||||
sk_SK.UTF-8/UTF-8 \
|
||||
sk_SK/ISO-8859-2 \
|
||||
sl_SI.UTF-8/UTF-8 \
|
||||
sl_SI/ISO-8859-2 \
|
||||
sm_WS/UTF-8 \
|
||||
so_DJ.UTF-8/UTF-8 \
|
||||
so_DJ/ISO-8859-1 \
|
||||
so_ET/UTF-8 \
|
||||
so_KE.UTF-8/UTF-8 \
|
||||
so_KE/ISO-8859-1 \
|
||||
so_SO.UTF-8/UTF-8 \
|
||||
so_SO/ISO-8859-1 \
|
||||
sq_AL.UTF-8/UTF-8 \
|
||||
sq_AL/ISO-8859-1 \
|
||||
sq_MK/UTF-8 \
|
||||
sr_ME/UTF-8 \
|
||||
sr_RS/UTF-8 \
|
||||
sr_RS@latin/UTF-8 \
|
||||
ss_ZA/UTF-8 \
|
||||
st_ZA.UTF-8/UTF-8 \
|
||||
st_ZA/ISO-8859-1 \
|
||||
sv_FI.UTF-8/UTF-8 \
|
||||
sv_FI/ISO-8859-1 \
|
||||
sv_FI@euro/ISO-8859-15 \
|
||||
sv_SE.UTF-8/UTF-8 \
|
||||
sv_SE/ISO-8859-1 \
|
||||
sv_SE.ISO-8859-15/ISO-8859-15 \
|
||||
sw_KE/UTF-8 \
|
||||
sw_TZ/UTF-8 \
|
||||
szl_PL/UTF-8 \
|
||||
ta_IN/UTF-8 \
|
||||
ta_LK/UTF-8 \
|
||||
tcy_IN.UTF-8/UTF-8 \
|
||||
te_IN/UTF-8 \
|
||||
tg_TJ.UTF-8/UTF-8 \
|
||||
tg_TJ/KOI8-T \
|
||||
th_TH.UTF-8/UTF-8 \
|
||||
th_TH/TIS-620 \
|
||||
the_NP/UTF-8 \
|
||||
ti_ER/UTF-8 \
|
||||
ti_ET/UTF-8 \
|
||||
tig_ER/UTF-8 \
|
||||
tk_TM/UTF-8 \
|
||||
tl_PH.UTF-8/UTF-8 \
|
||||
tl_PH/ISO-8859-1 \
|
||||
tn_ZA/UTF-8 \
|
||||
to_TO/UTF-8 \
|
||||
tpi_PG/UTF-8 \
|
||||
tr_CY.UTF-8/UTF-8 \
|
||||
tr_CY/ISO-8859-9 \
|
||||
tr_TR.UTF-8/UTF-8 \
|
||||
tr_TR/ISO-8859-9 \
|
||||
ts_ZA/UTF-8 \
|
||||
tt_RU/UTF-8 \
|
||||
tt_RU@iqtelif/UTF-8 \
|
||||
ug_CN/UTF-8 \
|
||||
uk_UA.UTF-8/UTF-8 \
|
||||
uk_UA/KOI8-U \
|
||||
unm_US/UTF-8 \
|
||||
ur_IN/UTF-8 \
|
||||
ur_PK/UTF-8 \
|
||||
uz_UZ.UTF-8/UTF-8 \
|
||||
uz_UZ/ISO-8859-1 \
|
||||
uz_UZ@cyrillic/UTF-8 \
|
||||
ve_ZA/UTF-8 \
|
||||
vi_VN/UTF-8 \
|
||||
wa_BE/ISO-8859-1 \
|
||||
wa_BE@euro/ISO-8859-15 \
|
||||
wa_BE.UTF-8/UTF-8 \
|
||||
wae_CH/UTF-8 \
|
||||
wal_ET/UTF-8 \
|
||||
wo_SN/UTF-8 \
|
||||
xh_ZA.UTF-8/UTF-8 \
|
||||
xh_ZA/ISO-8859-1 \
|
||||
yi_US.UTF-8/UTF-8 \
|
||||
yi_US/CP1255 \
|
||||
yo_NG/UTF-8 \
|
||||
yue_HK/UTF-8 \
|
||||
yuw_PG/UTF-8 \
|
||||
zh_CN.GB18030/GB18030 \
|
||||
zh_CN.GBK/GBK \
|
||||
zh_CN.UTF-8/UTF-8 \
|
||||
zh_CN/GB2312 \
|
||||
zh_HK.UTF-8/UTF-8 \
|
||||
zh_HK/BIG5-HKSCS \
|
||||
zh_SG.UTF-8/UTF-8 \
|
||||
zh_SG.GBK/GBK \
|
||||
zh_SG/GB2312 \
|
||||
zh_TW.EUC-TW/EUC-TW \
|
||||
zh_TW.UTF-8/UTF-8 \
|
||||
zh_TW/BIG5 \
|
||||
zu_ZA.UTF-8/UTF-8 \
|
||||
zu_ZA/ISO-8859-1 \
|
@ -0,0 +1,77 @@
|
||||
objpfx = $(prefix)/$(ver)/usr/libexec/glibc-benchtests/
|
||||
|
||||
bench-math := acos acosh asin asinh atan atanh cos cosh exp exp2 ffs ffsll \
|
||||
log log2 modf pow rint sin sincos sinh sqrt tan tanh
|
||||
|
||||
bench-pthread := pthread_once
|
||||
|
||||
bench := $(bench-math) $(bench-pthread)
|
||||
|
||||
run-bench := $(prefix)/$(ver)/lib64/ld-linux-x86-64.so.2 --library-path $(prefix)/$(ver)/lib64 $${run}
|
||||
|
||||
# String function benchmarks.
|
||||
string-bench := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
|
||||
mempcpy memset rawmemchr stpcpy stpncpy strcasecmp strcasestr \
|
||||
strcat strchr strchrnul strcmp strcpy strcspn strlen \
|
||||
strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \
|
||||
strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok
|
||||
string-bench-all := $(string-bench)
|
||||
|
||||
stdlib-bench := strtod
|
||||
|
||||
benchset := $(string-bench-all) $(stdlib-bench)
|
||||
|
||||
bench-malloc := malloc-thread
|
||||
|
||||
binaries-bench := $(addprefix $(objpfx)bench-,$(bench))
|
||||
binaries-benchset := $(addprefix $(objpfx)bench-,$(benchset))
|
||||
binaries-bench-malloc := $(addprefix $(objpfx)bench-,$(bench-malloc))
|
||||
|
||||
DETAILED_OPT :=
|
||||
|
||||
ifdef DETAILED
|
||||
DETAILED_OPT := -d
|
||||
endif
|
||||
|
||||
bench: bench-set bench-func bench-malloc
|
||||
|
||||
bench-set: $(binaries-benchset)
|
||||
for run in $^; do \
|
||||
outfile=$(prefix)/$$(basename $${run}.$(ver).out); \
|
||||
echo "Running $${run}"; \
|
||||
$(run-bench) > $${outfile}.tmp; \
|
||||
mv $${outfile}{.tmp,}; \
|
||||
done
|
||||
|
||||
bench-malloc: $(binaries-bench-malloc)
|
||||
run=$(objpfx)bench-malloc-thread; \
|
||||
outfile=$(prefix)/$$(basename $${run}.$(ver).out); \
|
||||
for thr in 1 8 16 32; do \
|
||||
echo "Running $${run} $${thr}"; \
|
||||
$(run-bench) $${thr} > $${outfile}.tmp; \
|
||||
mv $${outfile}{.tmp,}; \
|
||||
done
|
||||
|
||||
# Build and execute the benchmark functions. This target generates JSON
|
||||
# formatted bench.out. Each of the programs produce independent JSON output,
|
||||
# so one could even execute them individually and process it using any JSON
|
||||
# capable language or tool.
|
||||
bench-func: $(binaries-bench)
|
||||
{ echo "{\"timing_type\": \"hp-timing\","; \
|
||||
echo " \"functions\": {"; \
|
||||
for run in $^; do \
|
||||
if ! [ "x$${run}" = "x$<" ]; then \
|
||||
echo ","; \
|
||||
fi; \
|
||||
echo "Running $${run}" >&2; \
|
||||
$(run-bench) $(DETAILED_OPT); \
|
||||
done; \
|
||||
echo; \
|
||||
echo " }"; \
|
||||
echo "}"; } > $(prefix)/bench.$(ver).out-tmp; \
|
||||
if [ -f $(prefix)/bench.$(ver).out ]; then \
|
||||
mv -f $(prefix)/bench.$(ver).out{,.old}; \
|
||||
fi; \
|
||||
mv -f $(prefix)/bench.$(ver).out{-tmp,}
|
||||
# scripts/validate_benchout.py bench.out \
|
||||
# scripts/benchout.schema.json
|
@ -0,0 +1,862 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include "../locale/hashval.h"
|
||||
#define __LC_LAST 13
|
||||
#include "../locale/locarchive.h"
|
||||
#include "../crypt/md5.h"
|
||||
|
||||
const char *alias_file = DATADIR "/locale/locale.alias";
|
||||
const char *locar_file = PREFIX "/lib/locale/locale-archive";
|
||||
const char *tmpl_file = PREFIX "/lib/locale/locale-archive.tmpl";
|
||||
const char *loc_path = PREFIX "/lib/locale/";
|
||||
/* Flags set by `--verbose` option. */
|
||||
int be_quiet = 1;
|
||||
int verbose = 0;
|
||||
int max_locarchive_open_retry = 10;
|
||||
const char *output_prefix;
|
||||
|
||||
/* Endianness should have been taken care of by localedef. We don't need to do
|
||||
additional swapping. We need this variable exported however, since
|
||||
locarchive.c uses it to determine if it needs to swap endianness of a value
|
||||
before writing to or reading from the archive. */
|
||||
bool swap_endianness_p = false;
|
||||
|
||||
static const char *locnames[] =
|
||||
{
|
||||
#define DEFINE_CATEGORY(category, category_name, items, a) \
|
||||
[category] = category_name,
|
||||
#include "../locale/categories.def"
|
||||
#undef DEFINE_CATEGORY
|
||||
};
|
||||
|
||||
static int
|
||||
is_prime (unsigned long candidate)
|
||||
{
|
||||
/* No even number and none less than 10 will be passed here. */
|
||||
unsigned long int divn = 3;
|
||||
unsigned long int sq = divn * divn;
|
||||
|
||||
while (sq < candidate && candidate % divn != 0)
|
||||
{
|
||||
++divn;
|
||||
sq += 4 * divn;
|
||||
++divn;
|
||||
}
|
||||
|
||||
return candidate % divn != 0;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
next_prime (unsigned long seed)
|
||||
{
|
||||
/* Make it definitely odd. */
|
||||
seed |= 1;
|
||||
|
||||
while (!is_prime (seed))
|
||||
seed += 2;
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
void
|
||||
error (int status, int errnum, const char *message, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, message);
|
||||
fflush (stdout);
|
||||
fprintf (stderr, "%s: ", program_invocation_name);
|
||||
vfprintf (stderr, message, args);
|
||||
va_end (args);
|
||||
if (errnum)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
exit (errnum == EROFS ? 0 : status);
|
||||
}
|
||||
|
||||
void *
|
||||
xmalloc (size_t size)
|
||||
{
|
||||
void *p = malloc (size);
|
||||
if (p == NULL)
|
||||
error (EXIT_FAILURE, errno, "could not allocate %zd bytes of memory", size);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
open_tmpl_archive (struct locarhandle *ah)
|
||||
{
|
||||
struct stat64 st;
|
||||
int fd;
|
||||
struct locarhead head;
|
||||
const char *archivefname = ah->fname == NULL ? tmpl_file : ah->fname;
|
||||
|
||||
/* Open the archive. We must have exclusive write access. */
|
||||
fd = open64 (archivefname, O_RDONLY);
|
||||
if (fd == -1)
|
||||
error (EXIT_FAILURE, errno, "cannot open locale archive template file \"%s\"",
|
||||
archivefname);
|
||||
|
||||
if (fstat64 (fd, &st) < 0)
|
||||
error (EXIT_FAILURE, errno, "cannot stat locale archive template file \"%s\"",
|
||||
archivefname);
|
||||
|
||||
/* Read the header. */
|
||||
if (TEMP_FAILURE_RETRY (read (fd, &head, sizeof (head))) != sizeof (head))
|
||||
error (EXIT_FAILURE, errno, "cannot read archive header");
|
||||
|
||||
ah->fd = fd;
|
||||
ah->mmaped = (head.sumhash_offset
|
||||
+ head.sumhash_size * sizeof (struct sumhashent));
|
||||
if (ah->mmaped > (unsigned long) st.st_size)
|
||||
error (EXIT_FAILURE, 0, "locale archive template file truncated");
|
||||
ah->mmaped = st.st_size;
|
||||
ah->reserved = st.st_size;
|
||||
|
||||
/* Now we know how large the administrative information part is.
|
||||
Map all of it. */
|
||||
ah->addr = mmap64 (NULL, ah->mmaped, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (ah->addr == MAP_FAILED)
|
||||
error (EXIT_FAILURE, errno, "cannot map archive header");
|
||||
}
|
||||
|
||||
/* Open the locale archive. */
|
||||
extern void open_archive (struct locarhandle *ah, bool readonly);
|
||||
|
||||
/* Close the locale archive. */
|
||||
extern void close_archive (struct locarhandle *ah);
|
||||
|
||||
/* Add given locale data to the archive. */
|
||||
extern int add_locale_to_archive (struct locarhandle *ah, const char *name,
|
||||
locale_data_t data, bool replace);
|
||||
|
||||
extern void add_alias (struct locarhandle *ah, const char *alias,
|
||||
bool replace, const char *oldname,
|
||||
uint32_t *locrec_offset_p);
|
||||
|
||||
extern struct namehashent *
|
||||
insert_name (struct locarhandle *ah,
|
||||
const char *name, size_t name_len, bool replace);
|
||||
|
||||
struct nameent
|
||||
{
|
||||
char *name;
|
||||
struct locrecent *locrec;
|
||||
};
|
||||
|
||||
struct dataent
|
||||
{
|
||||
const unsigned char *sum;
|
||||
uint32_t file_offset;
|
||||
};
|
||||
|
||||
static int
|
||||
nameentcmp (const void *a, const void *b)
|
||||
{
|
||||
struct locrecent *la = ((const struct nameent *) a)->locrec;
|
||||
struct locrecent *lb = ((const struct nameent *) b)->locrec;
|
||||
uint32_t start_a = -1, end_a = 0;
|
||||
uint32_t start_b = -1, end_b = 0;
|
||||
int cnt;
|
||||
|
||||
for (cnt = 0; cnt < __LC_LAST; ++cnt)
|
||||
if (cnt != LC_ALL)
|
||||
{
|
||||
if (la->record[cnt].offset < start_a)
|
||||
start_a = la->record[cnt].offset;
|
||||
if (la->record[cnt].offset + la->record[cnt].len > end_a)
|
||||
end_a = la->record[cnt].offset + la->record[cnt].len;
|
||||
}
|
||||
assert (start_a != (uint32_t)-1);
|
||||
assert (end_a != 0);
|
||||
|
||||
for (cnt = 0; cnt < __LC_LAST; ++cnt)
|
||||
if (cnt != LC_ALL)
|
||||
{
|
||||
if (lb->record[cnt].offset < start_b)
|
||||
start_b = lb->record[cnt].offset;
|
||||
if (lb->record[cnt].offset + lb->record[cnt].len > end_b)
|
||||
end_b = lb->record[cnt].offset + lb->record[cnt].len;
|
||||
}
|
||||
assert (start_b != (uint32_t)-1);
|
||||
assert (end_b != 0);
|
||||
|
||||
if (start_a != start_b)
|
||||
return (int)start_a - (int)start_b;
|
||||
return (int)end_a - (int)end_b;
|
||||
}
|
||||
|
||||
static int
|
||||
dataentcmp (const void *a, const void *b)
|
||||
{
|
||||
if (((const struct dataent *) a)->file_offset
|
||||
< ((const struct dataent *) b)->file_offset)
|
||||
return -1;
|
||||
|
||||
if (((const struct dataent *) a)->file_offset
|
||||
> ((const struct dataent *) b)->file_offset)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sumsearchfn (const void *key, const void *ent)
|
||||
{
|
||||
uint32_t keyn = *(uint32_t *)key;
|
||||
uint32_t entn = ((struct dataent *)ent)->file_offset;
|
||||
|
||||
if (keyn < entn)
|
||||
return -1;
|
||||
if (keyn > entn)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
compute_data (struct locarhandle *ah, struct nameent *name, size_t sumused,
|
||||
struct dataent *files, locale_data_t data)
|
||||
{
|
||||
int cnt;
|
||||
struct locrecent *locrec = name->locrec;
|
||||
struct dataent *file;
|
||||
data[LC_ALL].addr = ((char *) ah->addr) + locrec->record[LC_ALL].offset;
|
||||
data[LC_ALL].size = locrec->record[LC_ALL].len;
|
||||
for (cnt = 0; cnt < __LC_LAST; ++cnt)
|
||||
if (cnt != LC_ALL)
|
||||
{
|
||||
data[cnt].addr = ((char *) ah->addr) + locrec->record[cnt].offset;
|
||||
data[cnt].size = locrec->record[cnt].len;
|
||||
if (data[cnt].addr >= data[LC_ALL].addr
|
||||
&& data[cnt].addr + data[cnt].size
|
||||
<= data[LC_ALL].addr + data[LC_ALL].size)
|
||||
__md5_buffer (data[cnt].addr, data[cnt].size, data[cnt].sum);
|
||||
else
|
||||
{
|
||||
file = bsearch (&locrec->record[cnt].offset, files, sumused,
|
||||
sizeof (*files), sumsearchfn);
|
||||
if (file == NULL)
|
||||
error (EXIT_FAILURE, 0, "inconsistent template file");
|
||||
memcpy (data[cnt].sum, file->sum, sizeof (data[cnt].sum));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
fill_archive (struct locarhandle *tmpl_ah,
|
||||
const char *fname,
|
||||
size_t install_langs_count, char *install_langs_list[],
|
||||
size_t nlist, char *list[],
|
||||
const char *primary)
|
||||
{
|
||||
struct locarhandle ah;
|
||||
struct locarhead *head;
|
||||
int result = 0;
|
||||
struct nameent *names;
|
||||
struct namehashent *namehashtab;
|
||||
size_t cnt, used;
|
||||
struct dataent *files;
|
||||
struct sumhashent *sumhashtab;
|
||||
size_t sumused;
|
||||
struct locrecent *primary_locrec = NULL;
|
||||
struct nameent *primary_nameent = NULL;
|
||||
|
||||
head = tmpl_ah->addr;
|
||||
names = (struct nameent *) malloc (head->namehash_used
|
||||
* sizeof (struct nameent));
|
||||
files = (struct dataent *) malloc (head->sumhash_used
|
||||
* sizeof (struct dataent));
|
||||
if (names == NULL || files == NULL)
|
||||
error (EXIT_FAILURE, errno, "could not allocate tables");
|
||||
|
||||
namehashtab = (struct namehashent *) ((char *) tmpl_ah->addr
|
||||
+ head->namehash_offset);
|
||||
sumhashtab = (struct sumhashent *) ((char *) tmpl_ah->addr
|
||||
+ head->sumhash_offset);
|
||||
|
||||
for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
|
||||
if (namehashtab[cnt].locrec_offset != 0)
|
||||
{
|
||||
char * name;
|
||||
int i;
|
||||
assert (used < head->namehash_used);
|
||||
name = tmpl_ah->addr + namehashtab[cnt].name_offset;
|
||||
if (install_langs_count == 0)
|
||||
{
|
||||
/* Always intstall the entry. */
|
||||
names[used].name = name;
|
||||
names[used++].locrec
|
||||
= (struct locrecent *) ((char *) tmpl_ah->addr +
|
||||
namehashtab[cnt].locrec_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only install the entry if the user asked for it via
|
||||
--install-langs. */
|
||||
for (i = 0; i < install_langs_count; i++)
|
||||
{
|
||||
/* Add one for "_" and one for the null terminator. */
|
||||
size_t len = strlen (install_langs_list[i]) + 2;
|
||||
char *install_lang = (char *)xmalloc (len);
|
||||
strcpy (install_lang, install_langs_list[i]);
|
||||
if (strchr (install_lang, '_') == NULL)
|
||||
strcat (install_lang, "_");
|
||||
if (strncmp (name, install_lang, strlen (install_lang)) == 0)
|
||||
{
|
||||
names[used].name = name;
|
||||
names[used++].locrec
|
||||
= (struct locrecent *) ((char *)tmpl_ah->addr
|
||||
+ namehashtab[cnt].locrec_offset);
|
||||
}
|
||||
free (install_lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the names. */
|
||||
qsort (names, used, sizeof (struct nameent), nameentcmp);
|
||||
|
||||
for (cnt = sumused = 0; cnt < head->sumhash_size; ++cnt)
|
||||
if (sumhashtab[cnt].file_offset != 0)
|
||||
{
|
||||
assert (sumused < head->sumhash_used);
|
||||
files[sumused].sum = (const unsigned char *) sumhashtab[cnt].sum;
|
||||
files[sumused++].file_offset = sumhashtab[cnt].file_offset;
|
||||
}
|
||||
|
||||
/* Sort by file locations. */
|
||||
qsort (files, sumused, sizeof (struct dataent), dataentcmp);
|
||||
|
||||
/* Open the archive. This call never returns if we cannot
|
||||
successfully open the archive. */
|
||||
ah.fname = NULL;
|
||||
if (fname != NULL)
|
||||
ah.fname = fname;
|
||||
open_archive (&ah, false);
|
||||
|
||||
if (primary != NULL)
|
||||
{
|
||||
for (cnt = 0; cnt < used; ++cnt)
|
||||
if (strcmp (names[cnt].name, primary) == 0)
|
||||
break;
|
||||
if (cnt < used)
|
||||
{
|
||||
locale_data_t data;
|
||||
|
||||
compute_data (tmpl_ah, &names[cnt], sumused, files, data);
|
||||
result |= add_locale_to_archive (&ah, primary, data, 0);
|
||||
primary_locrec = names[cnt].locrec;
|
||||
primary_nameent = &names[cnt];
|
||||
}
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < used; ++cnt)
|
||||
if (&names[cnt] == primary_nameent)
|
||||
continue;
|
||||
else if ((cnt > 0 && names[cnt - 1].locrec == names[cnt].locrec)
|
||||
|| names[cnt].locrec == primary_locrec)
|
||||
{
|
||||
const char *oldname;
|
||||
struct namehashent *namehashent;
|
||||
uint32_t locrec_offset;
|
||||
|
||||
if (names[cnt].locrec == primary_locrec)
|
||||
oldname = primary;
|
||||
else
|
||||
oldname = names[cnt - 1].name;
|
||||
namehashent = insert_name (&ah, oldname, strlen (oldname), true);
|
||||
assert (namehashent->name_offset != 0);
|
||||
assert (namehashent->locrec_offset != 0);
|
||||
locrec_offset = namehashent->locrec_offset;
|
||||
add_alias (&ah, names[cnt].name, 0, oldname, &locrec_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
locale_data_t data;
|
||||
|
||||
compute_data (tmpl_ah, &names[cnt], sumused, files, data);
|
||||
result |= add_locale_to_archive (&ah, names[cnt].name, data, 0);
|
||||
}
|
||||
|
||||
while (nlist-- > 0)
|
||||
{
|
||||
const char *fname = *list++;
|
||||
size_t fnamelen = strlen (fname);
|
||||
struct stat64 st;
|
||||
DIR *dirp;
|
||||
struct dirent64 *d;
|
||||
int seen;
|
||||
locale_data_t data;
|
||||
int cnt;
|
||||
|
||||
/* First see whether this really is a directory and whether it
|
||||
contains all the require locale category files. */
|
||||
if (stat64 (fname, &st) < 0)
|
||||
{
|
||||
error (0, 0, "stat of \"%s\" failed: %s: ignored", fname,
|
||||
strerror (errno));
|
||||
continue;
|
||||
}
|
||||
if (!S_ISDIR (st.st_mode))
|
||||
{
|
||||
error (0, 0, "\"%s\" is no directory; ignored", fname);
|
||||
continue;
|
||||
}
|
||||
|
||||
dirp = opendir (fname);
|
||||
if (dirp == NULL)
|
||||
{
|
||||
error (0, 0, "cannot open directory \"%s\": %s: ignored",
|
||||
fname, strerror (errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
seen = 0;
|
||||
while ((d = readdir64 (dirp)) != NULL)
|
||||
{
|
||||
for (cnt = 0; cnt < __LC_LAST; ++cnt)
|
||||
if (cnt != LC_ALL)
|
||||
if (strcmp (d->d_name, locnames[cnt]) == 0)
|
||||
{
|
||||
unsigned char d_type;
|
||||
|
||||
/* We have an object of the required name. If it's
|
||||
a directory we have to look at a file with the
|
||||
prefix "SYS_". Otherwise we have found what we
|
||||
are looking for. */
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
d_type = d->d_type;
|
||||
|
||||
if (d_type != DT_REG)
|
||||
#endif
|
||||
{
|
||||
char fullname[fnamelen + 2 * strlen (d->d_name) + 7];
|
||||
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
if (d_type == DT_UNKNOWN || d_type == DT_LNK)
|
||||
#endif
|
||||
{
|
||||
strcpy (stpcpy (stpcpy (fullname, fname), "/"),
|
||||
d->d_name);
|
||||
|
||||
if (stat64 (fullname, &st) == -1)
|
||||
/* We cannot stat the file, ignore it. */
|
||||
break;
|
||||
|
||||
d_type = IFTODT (st.st_mode);
|
||||
}
|
||||
|
||||
if (d_type == DT_DIR)
|
||||
{
|
||||
/* We have to do more tests. The file is a
|
||||
directory and it therefore must contain a
|
||||
regular file with the same name except a
|
||||
"SYS_" prefix. */
|
||||
char *t = stpcpy (stpcpy (fullname, fname), "/");
|
||||
strcpy (stpcpy (stpcpy (t, d->d_name), "/SYS_"),
|
||||
d->d_name);
|
||||
|
||||
if (stat64 (fullname, &st) == -1)
|
||||
/* There is no SYS_* file or we cannot
|
||||
access it. */
|
||||
break;
|
||||
|
||||
d_type = IFTODT (st.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found a regular file (eventually after
|
||||
following a symlink) we are successful. */
|
||||
if (d_type == DT_REG)
|
||||
++seen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir (dirp);
|
||||
|
||||
if (seen != __LC_LAST - 1)
|
||||
{
|
||||
/* We don't have all locale category files. Ignore the name. */
|
||||
error (0, 0, "incomplete set of locale files in \"%s\"",
|
||||
fname);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add the files to the archive. To do this we first compute
|
||||
sizes and the MD5 sums of all the files. */
|
||||
for (cnt = 0; cnt < __LC_LAST; ++cnt)
|
||||
if (cnt != LC_ALL)
|
||||
{
|
||||
char fullname[fnamelen + 2 * strlen (locnames[cnt]) + 7];
|
||||
int fd;
|
||||
|
||||
strcpy (stpcpy (stpcpy (fullname, fname), "/"), locnames[cnt]);
|
||||
fd = open64 (fullname, O_RDONLY);
|
||||
if (fd == -1 || fstat64 (fd, &st) == -1)
|
||||
{
|
||||
/* Cannot read the file. */
|
||||
if (fd != -1)
|
||||
close (fd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (S_ISDIR (st.st_mode))
|
||||
{
|
||||
char *t;
|
||||
close (fd);
|
||||
t = stpcpy (stpcpy (fullname, fname), "/");
|
||||
strcpy (stpcpy (stpcpy (t, locnames[cnt]), "/SYS_"),
|
||||
locnames[cnt]);
|
||||
|
||||
fd = open64 (fullname, O_RDONLY);
|
||||
if (fd == -1 || fstat64 (fd, &st) == -1
|
||||
|| !S_ISREG (st.st_mode))
|
||||
{
|
||||
if (fd != -1)
|
||||
close (fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map the file. */
|
||||
data[cnt].addr = mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
|
||||
fd, 0);
|
||||
if (data[cnt].addr == MAP_FAILED)
|
||||
{
|
||||
/* Cannot map it. */
|
||||
close (fd);
|
||||
break;
|
||||
}
|
||||
|
||||
data[cnt].size = st.st_size;
|
||||
__md5_buffer (data[cnt].addr, st.st_size, data[cnt].sum);
|
||||
|
||||
/* We don't need the file descriptor anymore. */
|
||||
close (fd);
|
||||
}
|
||||
|
||||
if (cnt != __LC_LAST)
|
||||
{
|
||||
while (cnt-- > 0)
|
||||
if (cnt != LC_ALL)
|
||||
munmap (data[cnt].addr, data[cnt].size);
|
||||
|
||||
error (0, 0, "cannot read all files in \"%s\": ignored", fname);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
result |= add_locale_to_archive (&ah, basename (fname), data, 0);
|
||||
|
||||
for (cnt = 0; cnt < __LC_LAST; ++cnt)
|
||||
if (cnt != LC_ALL)
|
||||
munmap (data[cnt].addr, data[cnt].size);
|
||||
}
|
||||
|
||||
/* We are done. */
|
||||
close_archive (&ah);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf ("\
|
||||
Usage: build-locale-archive [OPTION]... [TEMPLATE-FILE] [ARCHIVE-FILE]\n\
|
||||
Builds a locale archive from a template file.\n\
|
||||
Options:\n\
|
||||
-h, --help Print this usage message.\n\
|
||||
-v, --verbose Verbose execution.\n\
|
||||
-l, --install-langs=LIST Only include locales given in LIST into the \n\
|
||||
locale archive. LIST is a colon separated list\n\
|
||||
of locale prefixes, for example \"de:en:ja\".\n\
|
||||
The special argument \"all\" means to install\n\
|
||||
all languages and it must be present by itself.\n\
|
||||
If \"all\" is present with any other language it\n\
|
||||
will be treated as the name of a locale.\n\
|
||||
If the --install-langs option is missing, all\n\
|
||||
locales are installed. The colon separated list\n\
|
||||
can contain any strings matching the beginning of\n\
|
||||
locale names.\n\
|
||||
If a string does not contain a \"_\", it is added.\n\
|
||||
Examples:\n\
|
||||
--install-langs=\"en\"\n\
|
||||
installs en_US, en_US.iso88591,\n\
|
||||
en_US.iso885915, en_US.utf8,\n\
|
||||
en_GB ...\n\
|
||||
--install-langs=\"en_US.utf8\"\n\
|
||||
installs only en_US.utf8.\n\
|
||||
--install-langs=\"ko\"\n\
|
||||
installs ko_KR, ko_KR.euckr,\n\
|
||||
ko_KR.utf8 but *not* kok_IN\n\
|
||||
because \"ko\" does not contain\n\
|
||||
\"_\" and it is silently added\n\
|
||||
--install-langs\"ko:kok\"\n\
|
||||
installs ko_KR, ko_KR.euckr,\n\
|
||||
ko_KR.utf8, kok_IN, and\n\
|
||||
kok_IN.utf8.\n\
|
||||
--install-langs=\"POSIX\" will\n\
|
||||
installs *no* locales at all\n\
|
||||
because POSIX matches none of\n\
|
||||
the locales. Actually, any string\n\
|
||||
matching nothing will do that.\n\
|
||||
POSIX and C will always be\n\
|
||||
available because they are\n\
|
||||
builtin.\n\
|
||||
Aliases are installed as well,\n\
|
||||
i.e. --install-langs=\"de\"\n\
|
||||
will install not only every locale starting with\n\
|
||||
\"de\" but also the aliases \"deutsch\"\n\
|
||||
and and \"german\" although the latter does not\n\
|
||||
start with \"de\".\n\
|
||||
\n\
|
||||
If the arguments TEMPLATE-FILE and ARCHIVE-FILE are not given the locations\n\
|
||||
where the glibc used expects these files are used by default.\n\
|
||||
");
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
char path[4096];
|
||||
DIR *dirp;
|
||||
struct dirent64 *d;
|
||||
struct stat64 st;
|
||||
char *list[16384], *primary;
|
||||
char *lang;
|
||||
int install_langs_count = 0;
|
||||
int i;
|
||||
char *install_langs_arg, *ila_start;
|
||||
char **install_langs_list = NULL;
|
||||
unsigned int cnt = 0;
|
||||
struct locarhandle tmpl_ah;
|
||||
char *new_locar_fname = NULL;
|
||||
size_t loc_path_len = strlen (loc_path);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int c;
|
||||
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"install-langs", required_argument, 0, 'l'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
/* getopt_long stores the option index here. */
|
||||
int option_index = 0;
|
||||
|
||||
c = getopt_long (argc, argv, "vhl:",
|
||||
long_options, &option_index);
|
||||
|
||||
/* Detect the end of the options. */
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("unknown option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
usage ();
|
||||
exit (1);
|
||||
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
be_quiet = 0;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage ();
|
||||
exit (0);
|
||||
|
||||
case 'l':
|
||||
install_langs_arg = ila_start = strdup (optarg);
|
||||
/* If the argument to --install-lang is "all", do
|
||||
not limit the list of languages to install and install
|
||||
them all. We do not support installing a single locale
|
||||
called "all". */
|
||||
#define MAGIC_INSTALL_ALL "all"
|
||||
if (install_langs_arg != NULL
|
||||
&& install_langs_arg[0] != '\0'
|
||||
&& !(strncmp(install_langs_arg, MAGIC_INSTALL_ALL,
|
||||
strlen(MAGIC_INSTALL_ALL)) == 0
|
||||
&& strlen (install_langs_arg) == 3))
|
||||
{
|
||||
/* Count the number of languages we will install. */
|
||||
while (true)
|
||||
{
|
||||
lang = strtok(install_langs_arg, ":;,");
|
||||
if (lang == NULL)
|
||||
break;
|
||||
install_langs_count++;
|
||||
install_langs_arg = NULL;
|
||||
}
|
||||
free (ila_start);
|
||||
|
||||
/* Reject an entire string made up of delimiters. */
|
||||
if (install_langs_count == 0)
|
||||
break;
|
||||
|
||||
/* Copy the list. */
|
||||
install_langs_list = (char **)xmalloc (sizeof(char *) * install_langs_count);
|
||||
install_langs_arg = ila_start = strdup (optarg);
|
||||
install_langs_count = 0;
|
||||
while (true)
|
||||
{
|
||||
lang = strtok(install_langs_arg, ":;,");
|
||||
if (lang == NULL)
|
||||
break;
|
||||
install_langs_list[install_langs_count] = lang;
|
||||
install_langs_count++;
|
||||
install_langs_arg = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
/* getopt_long already printed an error message. */
|
||||
usage ();
|
||||
exit (0);
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
tmpl_ah.fname = NULL;
|
||||
if (optind < argc)
|
||||
tmpl_ah.fname = argv[optind];
|
||||
if (optind + 1 < argc)
|
||||
new_locar_fname = argv[optind + 1];
|
||||
if (verbose)
|
||||
{
|
||||
if (tmpl_ah.fname)
|
||||
printf("input archive file specified on command line: %s\n",
|
||||
tmpl_ah.fname);
|
||||
else
|
||||
printf("using default input archive file.\n");
|
||||
if (new_locar_fname)
|
||||
printf("output archive file specified on command line: %s\n",
|
||||
new_locar_fname);
|
||||
else
|
||||
printf("using default output archive file.\n");
|
||||
}
|
||||
|
||||
dirp = opendir (loc_path);
|
||||
if (dirp == NULL)
|
||||
error (EXIT_FAILURE, errno, "cannot open directory \"%s\"", loc_path);
|
||||
|
||||
open_tmpl_archive (&tmpl_ah);
|
||||
|
||||
if (new_locar_fname)
|
||||
unlink (new_locar_fname);
|
||||
else
|
||||
unlink (locar_file);
|
||||
primary = getenv ("LC_ALL");
|
||||
if (primary == NULL)
|
||||
primary = getenv ("LANG");
|
||||
if (primary != NULL)
|
||||
{
|
||||
if (strncmp (primary, "ja", 2) != 0
|
||||
&& strncmp (primary, "ko", 2) != 0
|
||||
&& strncmp (primary, "zh", 2) != 0)
|
||||
{
|
||||
char *ptr = malloc (strlen (primary) + strlen (".utf8") + 1), *p, *q;
|
||||
/* This leads to invalid locales sometimes:
|
||||
de_DE.iso885915@euro -> de_DE.utf8@euro */
|
||||
if (ptr != NULL)
|
||||
{
|
||||
p = ptr;
|
||||
q = primary;
|
||||
while (*q && *q != '.' && *q != '@')
|
||||
*p++ = *q++;
|
||||
if (*q == '.')
|
||||
while (*q && *q != '@')
|
||||
q++;
|
||||
p = stpcpy (p, ".utf8");
|
||||
strcpy (p, q);
|
||||
primary = ptr;
|
||||
}
|
||||
else
|
||||
primary = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (path, loc_path, loc_path_len);
|
||||
|
||||
while ((d = readdir64 (dirp)) != NULL)
|
||||
{
|
||||
if (strcmp (d->d_name, ".") == 0 || strcmp (d->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strchr (d->d_name, '_') == NULL)
|
||||
continue;
|
||||
|
||||
size_t d_name_len = strlen (d->d_name);
|
||||
if (loc_path_len + d_name_len + 1 > sizeof (path))
|
||||
{
|
||||
error (0, 0, "too long filename \"%s\"", d->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy (path + loc_path_len, d->d_name, d_name_len + 1);
|
||||
if (stat64 (path, &st) < 0)
|
||||
{
|
||||
error (0, errno, "cannot stat \"%s\"", path);
|
||||
continue;
|
||||
}
|
||||
if (! S_ISDIR (st.st_mode))
|
||||
continue;
|
||||
if (cnt == 16384)
|
||||
{
|
||||
error (0, 0, "too many directories in \"%s\"", loc_path);
|
||||
break;
|
||||
}
|
||||
list[cnt] = strdup (path);
|
||||
if (list[cnt] == NULL)
|
||||
{
|
||||
error (0, errno, "cannot add file to list \"%s\"", path);
|
||||
continue;
|
||||
}
|
||||
if (primary != NULL && cnt > 0 && strcmp (primary, d->d_name) == 0)
|
||||
{
|
||||
char *p = list[0];
|
||||
list[0] = list[cnt];
|
||||
list[cnt] = p;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
closedir (dirp);
|
||||
/* Store the archive to the file specified as the second argument on the
|
||||
command line or the default locale archive. */
|
||||
fill_archive (&tmpl_ah, new_locar_fname,
|
||||
install_langs_count, install_langs_list,
|
||||
cnt, list, primary);
|
||||
close_archive (&tmpl_ah);
|
||||
truncate (tmpl_file, 0);
|
||||
if (install_langs_count > 0)
|
||||
{
|
||||
free (ila_start);
|
||||
free (install_langs_list);
|
||||
}
|
||||
char *tz_argv[] = { "/usr/sbin/tzdata-update", NULL };
|
||||
execve (tz_argv[0], (char *const *)tz_argv, (char *const *)&tz_argv[1]);
|
||||
exit (0);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Wed Jul 4 16:16:57 2018 +0200
|
||||
|
||||
Makeconfig (ASFLAGS): Always append required assembler flags.
|
||||
|
||||
Submitted upstream here:
|
||||
|
||||
https://sourceware.org/ml/libc-alpha/2018-07/msg00077.html
|
||||
|
||||
Otherwise, we lose essential flags such as -Wa,--noexecstack due to
|
||||
the way += works in make due to the ASFLAGS command line override.
|
||||
|
||||
diff --git a/Makeconfig b/Makeconfig
|
||||
index b0b27f0113ac18b8..92e76d6200bbcd5b 100644
|
||||
--- a/Makeconfig
|
||||
+++ b/Makeconfig
|
||||
@@ -1047,7 +1047,7 @@ endif
|
||||
ifndef ASFLAGS
|
||||
ASFLAGS := $(filter -g% -fdebug-prefix-map=%,$(CFLAGS))
|
||||
endif
|
||||
-ASFLAGS += -Werror=undef $(ASFLAGS-config) $(asflags-cpu)
|
||||
+override ASFLAGS += -Werror=undef $(ASFLAGS-config) $(asflags-cpu)
|
||||
|
||||
ifndef BUILD_CC
|
||||
BUILD_CC = $(CC)
|
@ -0,0 +1,153 @@
|
||||
#!/usr/bin/bash
|
||||
# This script can be invoked as follows:
|
||||
#
|
||||
# glibc-bench-compare [options] <BUILD> [BUILD]
|
||||
#
|
||||
# Options may be one of the following:
|
||||
#
|
||||
# -t The BUILD arguments are task ids and not a version-release string
|
||||
# -a ARCH Do comparison for ARCH architecture
|
||||
#
|
||||
# If any of the above options are given, both BUILD arguments must be given.
|
||||
# Otherwise, if only one BUILD is specified, then it is compared against the
|
||||
# installed glibc.
|
||||
|
||||
# Silence the pushd/popd messages
|
||||
pushd() {
|
||||
command pushd "$@" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
popd() {
|
||||
command popd "$@" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Clean up any downloaded files before we exit
|
||||
trap "rm -rf /tmp/glibc-bench-compare.$BASHPID.*" EXIT
|
||||
|
||||
task=0
|
||||
arch=$(uname -i)
|
||||
options=0
|
||||
path=0
|
||||
installed=
|
||||
|
||||
# Look for any commandline options
|
||||
while getopts ":tpa:" opt; do
|
||||
case $opt in
|
||||
p)
|
||||
path=1
|
||||
;;
|
||||
t)
|
||||
task=1
|
||||
options=1
|
||||
echo "Not implemented."
|
||||
exit 1
|
||||
;;
|
||||
a)
|
||||
arch=$OPTARG
|
||||
options=1
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Done, now shift all option arguments out.
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [ $# -gt 2 ] || [ $# -eq 0 ] || [ $# -lt 2 -a $options -eq 1 ]; then
|
||||
echo "Usage: $0 [OPTIONS] <old> [new]"
|
||||
echo
|
||||
echo "OPTIONS:"
|
||||
echo -e "\t-t\tCompare two brew tasks"
|
||||
echo -e "\t-a ARCH\tGet rpms for the ARCH architecture"
|
||||
echo -e "\t-p\tCompare built rpms in two paths."
|
||||
echo -e "\t\tThis minimally needs glibc, glibc-common and glibc-benchtests"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $2 ]; then
|
||||
new="$1"
|
||||
old=$(rpm --queryformat "%{VERSION}-%{RELEASE}\n" -q glibc | head -1)
|
||||
installed=$old
|
||||
else
|
||||
new="$2"
|
||||
old="$1"
|
||||
fi
|
||||
|
||||
decompress_rpms() {
|
||||
# We were given a path to the rpms. Figure out the version-release and
|
||||
# decompress the rpms.
|
||||
if [ -n $1 ]; then
|
||||
vr=$(rpm --queryformat="%{VERSION}-%{RELEASE}" -qp $1/glibc-2*.rpm | head -1)
|
||||
mkdir $vr && pushd $vr
|
||||
fi
|
||||
|
||||
for r in $1*.rpm; do
|
||||
( rpm2cpio $r | cpio -di ) > /dev/null
|
||||
done
|
||||
|
||||
if [ -n $1 ]; then
|
||||
popd
|
||||
echo $vr
|
||||
fi
|
||||
}
|
||||
|
||||
# Get rpms for a build and decompress them
|
||||
get_build() {
|
||||
echo "Processing build $1"
|
||||
mkdir $1 && pushd $1
|
||||
brew buildinfo "glibc-$1" |
|
||||
sed -n -e "s|/mnt/koji\(.\+$arch.\+\)|http://kojipkgs.fedoraproject.org\1|p" |
|
||||
while read url; do
|
||||
echo "Downloading $url"
|
||||
wget -q $url
|
||||
done
|
||||
decompress_rpms
|
||||
|
||||
echo "Removing rpms"
|
||||
rm -f $1/*.rpm
|
||||
|
||||
popd
|
||||
}
|
||||
|
||||
# Run benchmarks for a build
|
||||
run_bench() {
|
||||
if [ -z $1 ]; then
|
||||
make DETAILED=1 ver=$installed prefix= -f /usr/libexec/glibc-benchtests/bench.mk bench
|
||||
else
|
||||
make DETAILED=1 ver=$1 prefix=$PWD -f $1/usr/libexec/glibc-benchtests/bench.mk bench
|
||||
fi
|
||||
}
|
||||
|
||||
# Get absolute paths if needed, since we will change into the working directory
|
||||
# next.
|
||||
if [ $path -eq 1 ]; then
|
||||
old_path=$(realpath $old)/
|
||||
new_path=$(realpath $new)/
|
||||
fi
|
||||
|
||||
tmpdir=$(mktemp -p /tmp -d glibc-bench-compare.$$.XXXX)
|
||||
pushd $tmpdir
|
||||
|
||||
# Get both builds.
|
||||
if [ $path -eq 0 ]; then
|
||||
if [ -z $installed ]; then
|
||||
get_build $old
|
||||
fi
|
||||
get_build $new
|
||||
else
|
||||
old=$(decompress_rpms $old_path)
|
||||
new=$(decompress_rpms $new_path)
|
||||
fi
|
||||
|
||||
# make bench for each of those.
|
||||
if [ -z $installed ]; then
|
||||
run_bench $old
|
||||
else
|
||||
run_bench
|
||||
fi
|
||||
run_bench $new
|
||||
|
||||
# Now run the comparison script.
|
||||
$old/usr/libexec/glibc-benchtests/compare_bench.py $old/usr/libexec/glibc-benchtests/benchout.schema.json \
|
||||
bench.$old.out bench.$new.out
|
@ -0,0 +1,286 @@
|
||||
Short description: Add C.UTF-8 support.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-submitted
|
||||
|
||||
This patch needs to upstream as part of Carlos O'Donell
|
||||
<carlos@redhat.com>'s work on enabling upstream C.UTF-8 support. This
|
||||
work is currently blocked on cleaning up the test results to prove that
|
||||
full code-point sorting is working as intended.
|
||||
|
||||
Note that this patch does not provide full code-point sorting as
|
||||
expected.
|
||||
|
||||
This patch needs to upstream as soon as possible since it would be nice
|
||||
to have this in F29 and fixed.
|
||||
|
||||
From 2eda7b462b415105f5a05c1323372d4e39d46439 Mon Sep 17 00:00:00 2001
|
||||
From: Mike FABIAN <mfabian@redhat.com>
|
||||
Date: Mon, 10 Aug 2015 15:58:12 +0200
|
||||
Subject: [PATCH] Add a C.UTF-8 locale
|
||||
|
||||
---
|
||||
localedata/SUPPORTED | 1 +
|
||||
localedata/locales/C | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 239 insertions(+)
|
||||
create mode 100644 localedata/locales/C
|
||||
|
||||
diff --git a/localedata/SUPPORTED b/localedata/SUPPORTED
|
||||
index 8ca023e..2a78391 100644
|
||||
--- a/localedata/SUPPORTED
|
||||
+++ b/localedata/SUPPORTED
|
||||
@@ -1,6 +1,7 @@
|
||||
# This file names the currently supported and somewhat tested locales.
|
||||
# If you have any additions please file a glibc bug report.
|
||||
SUPPORTED-LOCALES=\
|
||||
+C.UTF-8/UTF-8 \
|
||||
aa_DJ.UTF-8/UTF-8 \
|
||||
aa_DJ/ISO-8859-1 \
|
||||
aa_ER/UTF-8 \
|
||||
diff --git a/localedata/locales/C b/localedata/locales/C
|
||||
new file mode 100644
|
||||
index 0000000..fdf460e
|
||||
--- /dev/null
|
||||
+++ b/localedata/locales/C
|
||||
@@ -0,0 +1,238 @@
|
||||
+escape_char /
|
||||
+comment_char %
|
||||
+% Locale for C locale in UTF-8
|
||||
+
|
||||
+LC_IDENTIFICATION
|
||||
+title "C locale"
|
||||
+source ""
|
||||
+address ""
|
||||
+contact ""
|
||||
+email "mfabian@redhat.com"
|
||||
+tel ""
|
||||
+fax ""
|
||||
+language "C"
|
||||
+territory ""
|
||||
+revision "1.0"
|
||||
+date "2015-08-10"
|
||||
+%
|
||||
+category "i18n:2012";LC_IDENTIFICATION
|
||||
+category "i18n:2012";LC_CTYPE
|
||||
+category "i18n:2012";LC_COLLATE
|
||||
+category "i18n:2012";LC_TIME
|
||||
+category "i18n:2012";LC_NUMERIC
|
||||
+category "i18n:2012";LC_MONETARY
|
||||
+category "i18n:2012";LC_MESSAGES
|
||||
+category "i18n:2012";LC_PAPER
|
||||
+category "i18n:2012";LC_NAME
|
||||
+category "i18n:2012";LC_ADDRESS
|
||||
+category "i18n:2012";LC_TELEPHONE
|
||||
+category "i18n:2012";LC_MEASUREMENT
|
||||
+END LC_IDENTIFICATION
|
||||
+
|
||||
+LC_CTYPE
|
||||
+copy "i18n"
|
||||
+
|
||||
+translit_start
|
||||
+include "translit_combining";""
|
||||
+translit_end
|
||||
+
|
||||
+END LC_CTYPE
|
||||
+
|
||||
+LC_COLLATE
|
||||
+order_start forward
|
||||
+<U0000>
|
||||
+..
|
||||
+<UFFFF>
|
||||
+<U10000>
|
||||
+..
|
||||
+<U1FFFF>
|
||||
+<U20000>
|
||||
+..
|
||||
+<U2FFFF>
|
||||
+<UE0000>
|
||||
+..
|
||||
+<UEFFFF>
|
||||
+<UF0000>
|
||||
+..
|
||||
+<UFFFFF>
|
||||
+<U100000>
|
||||
+..
|
||||
+<U10FFFF>
|
||||
+UNDEFINED
|
||||
+order_end
|
||||
+END LC_COLLATE
|
||||
+
|
||||
+LC_MONETARY
|
||||
+% This is the 14652 i18n fdcc-set definition for
|
||||
+% the LC_MONETARY category
|
||||
+% (except for the int_curr_symbol and currency_symbol, they are empty in
|
||||
+% the 14652 i18n fdcc-set definition and also empty in
|
||||
+% glibc/locale/C-monetary.c. But localedef complains in that case).
|
||||
+%
|
||||
+% Using "USD" for int_curr_symbol. But maybe "XXX" would be better?
|
||||
+% XXX is "No currency" (https://en.wikipedia.org/wiki/ISO_4217)
|
||||
+int_curr_symbol "<U0055><U0053><U0044><U0020>"
|
||||
+% Using "$" for currency_symbol. But maybe <U00A4> would be better?
|
||||
+% U+00A4 is the "generic currency symbol"
|
||||
+% (https://en.wikipedia.org/wiki/Currency_sign_%28typography%29)
|
||||
+currency_symbol "<U0024>"
|
||||
+mon_decimal_point "<U002E>"
|
||||
+mon_thousands_sep ""
|
||||
+mon_grouping -1
|
||||
+positive_sign ""
|
||||
+negative_sign "<U002D>"
|
||||
+int_frac_digits -1
|
||||
+frac_digits -1
|
||||
+p_cs_precedes -1
|
||||
+int_p_sep_by_space -1
|
||||
+p_sep_by_space -1
|
||||
+n_cs_precedes -1
|
||||
+int_n_sep_by_space -1
|
||||
+n_sep_by_space -1
|
||||
+p_sign_posn -1
|
||||
+n_sign_posn -1
|
||||
+%
|
||||
+END LC_MONETARY
|
||||
+
|
||||
+LC_NUMERIC
|
||||
+% This is the POSIX Locale definition for
|
||||
+% the LC_NUMERIC category.
|
||||
+%
|
||||
+decimal_point "<U002E>"
|
||||
+thousands_sep ""
|
||||
+grouping -1
|
||||
+END LC_NUMERIC
|
||||
+
|
||||
+LC_TIME
|
||||
+% This is the POSIX Locale definition for
|
||||
+% the LC_TIME category.
|
||||
+%
|
||||
+% Abbreviated weekday names (%a)
|
||||
+abday "<U0053><U0075><U006E>";"<U004D><U006F><U006E>";/
|
||||
+ "<U0054><U0075><U0065>";"<U0057><U0065><U0064>";/
|
||||
+ "<U0054><U0068><U0075>";"<U0046><U0072><U0069>";/
|
||||
+ "<U0053><U0061><U0074>"
|
||||
+
|
||||
+% Full weekday names (%A)
|
||||
+day "<U0053><U0075><U006E><U0064><U0061><U0079>";/
|
||||
+ "<U004D><U006F><U006E><U0064><U0061><U0079>";/
|
||||
+ "<U0054><U0075><U0065><U0073><U0064><U0061><U0079>";/
|
||||
+ "<U0057><U0065><U0064><U006E><U0065><U0073><U0064><U0061><U0079>";/
|
||||
+ "<U0054><U0068><U0075><U0072><U0073><U0064><U0061><U0079>";/
|
||||
+ "<U0046><U0072><U0069><U0064><U0061><U0079>";/
|
||||
+ "<U0053><U0061><U0074><U0075><U0072><U0064><U0061><U0079>"
|
||||
+
|
||||
+% Abbreviated month names (%b)
|
||||
+abmon "<U004A><U0061><U006E>";"<U0046><U0065><U0062>";/
|
||||
+ "<U004D><U0061><U0072>";"<U0041><U0070><U0072>";/
|
||||
+ "<U004D><U0061><U0079>";"<U004A><U0075><U006E>";/
|
||||
+ "<U004A><U0075><U006C>";"<U0041><U0075><U0067>";/
|
||||
+ "<U0053><U0065><U0070>";"<U004F><U0063><U0074>";/
|
||||
+ "<U004E><U006F><U0076>";"<U0044><U0065><U0063>"
|
||||
+
|
||||
+% Full month names (%B)
|
||||
+mon "<U004A><U0061><U006E><U0075><U0061><U0072><U0079>";/
|
||||
+ "<U0046><U0065><U0062><U0072><U0075><U0061><U0072><U0079>";/
|
||||
+ "<U004D><U0061><U0072><U0063><U0068>";/
|
||||
+ "<U0041><U0070><U0072><U0069><U006C>";/
|
||||
+ "<U004D><U0061><U0079>";/
|
||||
+ "<U004A><U0075><U006E><U0065>";/
|
||||
+ "<U004A><U0075><U006C><U0079>";/
|
||||
+ "<U0041><U0075><U0067><U0075><U0073><U0074>";/
|
||||
+ "<U0053><U0065><U0070><U0074><U0065><U006D><U0062><U0065><U0072>";/
|
||||
+ "<U004F><U0063><U0074><U006F><U0062><U0065><U0072>";/
|
||||
+ "<U004E><U006F><U0076><U0065><U006D><U0062><U0065><U0072>";/
|
||||
+ "<U0044><U0065><U0063><U0065><U006D><U0062><U0065><U0072>"
|
||||
+
|
||||
+% Week description, consists of three fields:
|
||||
+% 1. Number of days in a week.
|
||||
+% 2. Gregorian date that is a first weekday (19971130 for Sunday, 19971201 for Monday).
|
||||
+% 3. The weekday number to be contained in the first week of the year.
|
||||
+%
|
||||
+% ISO 8601 conforming applications should use the values 7, 19971201 (a
|
||||
+% Monday), and 4 (Thursday), respectively.
|
||||
+week 7;19971201;4
|
||||
+first_weekday 1
|
||||
+first_workday 1
|
||||
+
|
||||
+% Appropriate date and time representation (%c)
|
||||
+% "%a %b %e %H:%M:%S %Y"
|
||||
+d_t_fmt "<U0025><U0061><U0020><U0025><U0062><U0020><U0025><U0065><U0020><U0025><U0048><U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U0059>"
|
||||
+
|
||||
+% Appropriate date representation (%x)
|
||||
+% "%m/%d/%y"
|
||||
+d_fmt "<U0025><U006D><U002F><U0025><U0064><U002F><U0025><U0079>"
|
||||
+
|
||||
+% Appropriate time representation (%X)
|
||||
+% "%H:%M:%S"
|
||||
+t_fmt "<U0025><U0048><U003A><U0025><U004D><U003A><U0025><U0053>"
|
||||
+
|
||||
+% Appropriate AM/PM time representation (%r)
|
||||
+% "%I:%M:%S %p"
|
||||
+t_fmt_ampm "<U0025><U0049><U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U0070>"
|
||||
+
|
||||
+% Equivalent of AM/PM (%p) "AM"/"PM"
|
||||
+%
|
||||
+am_pm "<U0041><U004D>";"<U0050><U004D>"
|
||||
+
|
||||
+% Appropriate date representation (date(1)) "%a %b %e %H:%M:%S %Z %Y"
|
||||
+date_fmt "<U0025><U0061><U0020><U0025><U0062><U0020><U0025><U0065><U0020><U0025><U0048><U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A><U0020><U0025><U0059>"
|
||||
+END LC_TIME
|
||||
+
|
||||
+LC_MESSAGES
|
||||
+% This is the POSIX Locale definition for
|
||||
+% the LC_NUMERIC category.
|
||||
+%
|
||||
+yesexpr "<U005E><U005B><U0079><U0059><U005D>"
|
||||
+noexpr "<U005E><U005B><U006E><U004E><U005D>"
|
||||
+yesstr "<U0059><U0065><U0073>"
|
||||
+nostr "<U004E><U006F>"
|
||||
+END LC_MESSAGES
|
||||
+
|
||||
+LC_PAPER
|
||||
+% This is the ISO/IEC 14652 "i18n" definition for
|
||||
+% the LC_PAPER category.
|
||||
+% (A4 paper, this is also used in the built in C/POSIX
|
||||
+% locale in glibc/locale/C-paper.c)
|
||||
+height 297
|
||||
+width 210
|
||||
+END LC_PAPER
|
||||
+
|
||||
+LC_NAME
|
||||
+% This is the ISO/IEC 14652 "i18n" definition for
|
||||
+% the LC_NAME category.
|
||||
+% "%p%t%g%t%m%t%f"
|
||||
+% (also used in the built in C/POSIX locale in glibc/locale/C-name.c)
|
||||
+name_fmt "<U0025><U0070><U0025><U0074><U0025><U0067><U0025><U0074>/
|
||||
+<U0025><U006D><U0025><U0074><U0025><U0066>"
|
||||
+END LC_NAME
|
||||
+
|
||||
+LC_ADDRESS
|
||||
+% This is the ISO/IEC 14652 "i18n" definition for
|
||||
+% the LC_ADDRESS category.
|
||||
+% "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N"
|
||||
+% (also used in the built in C/POSIX locale in glibc/locale/C-address.c)
|
||||
+postal_fmt "<U0025><U0061><U0025><U004E><U0025><U0066><U0025><U004E>/
|
||||
+<U0025><U0064><U0025><U004E><U0025><U0062><U0025><U004E><U0025><U0073>/
|
||||
+<U0020><U0025><U0068><U0020><U0025><U0065><U0020><U0025><U0072><U0025>/
|
||||
+<U004E><U0025><U0043><U002D><U0025><U007A><U0020><U0025><U0054><U0025>/
|
||||
+<U004E><U0025><U0063><U0025><U004E>"
|
||||
+END LC_ADDRESS
|
||||
+
|
||||
+LC_TELEPHONE
|
||||
+% This is the ISO/IEC 14652 "i18n" definition for
|
||||
+% the LC_TELEPHONE category.
|
||||
+% "+%c %a %l"
|
||||
+tel_int_fmt "<U002B><U0025><U0063><U0020><U0025><U0061><U0020><U0025>/
|
||||
+<U006C>"
|
||||
+% (also used in the built in C/POSIX locale in glibc/locale/C-telephone.c)
|
||||
+END LC_TELEPHONE
|
||||
+
|
||||
+LC_MEASUREMENT
|
||||
+% This is the ISO/IEC 14652 "i18n" definition for
|
||||
+% the LC_MEASUREMENT category.
|
||||
+% (same as in the built in C/POSIX locale in glibc/locale/C-measurement.c)
|
||||
+%metric
|
||||
+measurement 1
|
||||
+END LC_MEASUREMENT
|
||||
+
|
||||
--
|
||||
2.4.3
|
||||
|
@ -0,0 +1,15 @@
|
||||
Short description: Adjust CS_PATH return value.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-needed
|
||||
|
||||
In Fedora we should return only /usr/bin because /bin is just a symlink
|
||||
to /usr/bin after MoveToUsr transition (which glibc has not really
|
||||
completed).
|
||||
|
||||
diff -pruN a/sysdeps/unix/confstr.h b/sysdeps/unix/confstr.h
|
||||
--- a/sysdeps/unix/confstr.h 2012-12-25 08:32:13.000000000 +0530
|
||||
+++ b/sysdeps/unix/confstr.h 2014-09-05 20:02:55.698275219 +0530
|
||||
@@ -1 +1 @@
|
||||
-#define CS_PATH "/bin:/usr/bin"
|
||||
+#define CS_PATH "/usr/bin"
|
@ -0,0 +1,91 @@
|
||||
Short description: Cleanup use of _dl_starting_up.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: https://sourceware.org/ml/libc-alpha/2014-02/msg00589.html
|
||||
|
||||
Upstream discussions:
|
||||
https://sourceware.org/ml/libc-alpha/2014-02/msg00580.html
|
||||
|
||||
Based on the following commit:
|
||||
~~~
|
||||
From 16552c01a66633c9e412984d9d92616bd4e5303c Mon Sep 17 00:00:00 2001
|
||||
From: Andreas Schwab <schwab@redhat.com>
|
||||
Date: Fri, 11 Jun 2010 11:04:11 +0200
|
||||
Subject: [PATCH] Properly set __libc_multiple_libcs
|
||||
|
||||
* elf/rtld.c (_dl_starting_up): Always define.
|
||||
(dl_main): Always set _dl_starting_up.
|
||||
* elf/dl-support.c (_dl_starting_up): Always define.
|
||||
* elf/dl-init.c (_dl_init): Always clear _dl_starting_up.
|
||||
|
||||
---
|
||||
ChangeLog | 7 +++++++
|
||||
elf/dl-init.c | 4 ----
|
||||
elf/dl-support.c | 2 --
|
||||
elf/rtld.c | 4 ----
|
||||
4 files changed, 7 insertions(+), 10 deletions(-)
|
||||
~~~
|
||||
|
||||
This patch needs to go upstream to get cleaned up, but has always involed
|
||||
analysis of the GNU/Hurd parts of the change and that stalled out, but
|
||||
perhaps with build-many-glibcs we can now test these changes more easily.
|
||||
|
||||
Index: b/elf/dl-init.c
|
||||
===================================================================
|
||||
--- a/elf/dl-init.c
|
||||
+++ b/elf/dl-init.c
|
||||
@@ -119,8 +119,6 @@ _dl_init (struct link_map *main_map, int
|
||||
while (i-- > 0)
|
||||
call_init (main_map->l_initfini[i], argc, argv, env);
|
||||
|
||||
-#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Finished starting up. */
|
||||
_dl_starting_up = 0;
|
||||
-#endif
|
||||
}
|
||||
Index: b/elf/dl-support.c
|
||||
===================================================================
|
||||
--- a/elf/dl-support.c
|
||||
+++ b/elf/dl-support.c
|
||||
@@ -117,10 +117,8 @@ struct r_scope_elem _dl_initial_searchli
|
||||
.r_nlist = 1,
|
||||
};
|
||||
|
||||
-#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Nonzero during startup. */
|
||||
int _dl_starting_up = 1;
|
||||
-#endif
|
||||
|
||||
/* Random data provided by the kernel. */
|
||||
void *_dl_random;
|
||||
Index: b/elf/rtld.c
|
||||
===================================================================
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -214,7 +214,6 @@ audit_list_iter_next (struct audit_list_
|
||||
return iter->previous->name;
|
||||
}
|
||||
|
||||
-#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Set nonzero during loading and initialization of executable and
|
||||
libraries, cleared before the executable's entry point runs. This
|
||||
must not be initialized to nonzero, because the unused dynamic
|
||||
@@ -224,7 +223,6 @@ audit_list_iter_next (struct audit_list_
|
||||
never be called. */
|
||||
int _dl_starting_up = 0;
|
||||
rtld_hidden_def (_dl_starting_up)
|
||||
-#endif
|
||||
|
||||
/* This is the structure which defines all variables global to ld.so
|
||||
(except those which cannot be added for some reason). */
|
||||
@@ -898,10 +896,8 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
/* Process the environment variable which control the behaviour. */
|
||||
process_envvars (&mode);
|
||||
|
||||
-#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Set up a flag which tells we are just starting. */
|
||||
_dl_starting_up = 1;
|
||||
-#endif
|
||||
|
||||
if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
|
||||
{
|
@ -0,0 +1,61 @@
|
||||
Short description: Fedora-specific workaround for kernel pty bug.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-submitted
|
||||
|
||||
This is a Fedora-specific workaround for a kernel bug where calling
|
||||
ioctl on a pty will silently ignore the invalid c_cflag. The
|
||||
workaround is to use TCGETS to verify the setting matches. This is
|
||||
not upstream and needs to either be removed or submitted upstream
|
||||
after analysis.
|
||||
|
||||
Index: b/sysdeps/unix/sysv/linux/tcsetattr.c
|
||||
===================================================================
|
||||
--- a/sysdeps/unix/sysv/linux/tcsetattr.c
|
||||
+++ b/sysdeps/unix/sysv/linux/tcsetattr.c
|
||||
@@ -45,6 +45,7 @@ __tcsetattr (int fd, int optional_action
|
||||
{
|
||||
struct __kernel_termios k_termios;
|
||||
unsigned long int cmd;
|
||||
+ int retval;
|
||||
|
||||
switch (optional_actions)
|
||||
{
|
||||
@@ -75,7 +76,36 @@ __tcsetattr (int fd, int optional_action
|
||||
memcpy (&k_termios.c_cc[0], &termios_p->c_cc[0],
|
||||
__KERNEL_NCCS * sizeof (cc_t));
|
||||
|
||||
- return INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios);
|
||||
+ retval = INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios);
|
||||
+
|
||||
+ if (retval == 0 && cmd == TCSETS)
|
||||
+ {
|
||||
+ /* The Linux kernel has a bug which silently ignore the invalid
|
||||
+ c_cflag on pty. We have to check it here. */
|
||||
+ int save = errno;
|
||||
+ retval = INLINE_SYSCALL (ioctl, 3, fd, TCGETS, &k_termios);
|
||||
+ if (retval)
|
||||
+ {
|
||||
+ /* We cannot verify if the setting is ok. We don't return
|
||||
+ an error (?). */
|
||||
+ __set_errno (save);
|
||||
+ retval = 0;
|
||||
+ }
|
||||
+ else if ((termios_p->c_cflag & (PARENB | CREAD))
|
||||
+ != (k_termios.c_cflag & (PARENB | CREAD))
|
||||
+ || ((termios_p->c_cflag & CSIZE)
|
||||
+ && ((termios_p->c_cflag & CSIZE)
|
||||
+ != (k_termios.c_cflag & CSIZE))))
|
||||
+ {
|
||||
+ /* It looks like the Linux kernel silently changed the
|
||||
+ PARENB/CREAD/CSIZE bits in c_cflag. Report it as an
|
||||
+ error. */
|
||||
+ __set_errno (EINVAL);
|
||||
+ retval = -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return retval;
|
||||
}
|
||||
weak_alias (__tcsetattr, tcsetattr)
|
||||
libc_hidden_def (tcsetattr)
|
@ -0,0 +1,49 @@
|
||||
Short description: Add 4 ISO-8859-15 locales to SUPPORTED for Euro symbol.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Bug-RHEL: #61908
|
||||
Upstream status: not-needed
|
||||
|
||||
Very early RHL 7.3 requirement to add these locales so users can
|
||||
get access to Euro symbol. We should review this bug and decide if
|
||||
the UTF-8 locales are now serving the same purpose and drop the
|
||||
additional locales.
|
||||
|
||||
* Tue Mar 26 2002 Jakub Jelinek <jakub@redhat.com> 2.2.5-28
|
||||
- add a couple of .ISO-8859-15 locales (#61908)
|
||||
|
||||
diff -Nrup a/localedata/SUPPORTED b/localedata/SUPPORTED
|
||||
--- a/localedata/SUPPORTED 2012-11-25 12:59:31.000000000 -0700
|
||||
+++ b/localedata/SUPPORTED 2012-11-26 12:58:43.298223018 -0700
|
||||
@@ -89,6 +89,7 @@ cy_GB.UTF-8/UTF-8 \
|
||||
cy_GB/ISO-8859-14 \
|
||||
da_DK.UTF-8/UTF-8 \
|
||||
da_DK/ISO-8859-1 \
|
||||
+da_DK.ISO-8859-15/ISO-8859-15 \
|
||||
de_AT.UTF-8/UTF-8 \
|
||||
de_AT/ISO-8859-1 \
|
||||
de_AT@euro/ISO-8859-15 \
|
||||
@@ -121,6 +122,7 @@ en_DK.UTF-8/UTF-8 \
|
||||
en_DK/ISO-8859-1 \
|
||||
en_GB.UTF-8/UTF-8 \
|
||||
en_GB/ISO-8859-1 \
|
||||
+en_GB.ISO-8859-15/ISO-8859-15 \
|
||||
en_HK.UTF-8/UTF-8 \
|
||||
en_HK/ISO-8859-1 \
|
||||
en_IE.UTF-8/UTF-8 \
|
||||
@@ -136,6 +138,7 @@ en_SG.UTF-8/UTF-8 \
|
||||
en_SG/ISO-8859-1 \
|
||||
en_US.UTF-8/UTF-8 \
|
||||
en_US/ISO-8859-1 \
|
||||
+en_US.ISO-8859-15/ISO-8859-15 \
|
||||
en_ZA.UTF-8/UTF-8 \
|
||||
en_ZA/ISO-8859-1 \
|
||||
en_ZM/UTF-8 \
|
||||
@@ -385,6 +388,7 @@ sv_FI/ISO-8859-1 \
|
||||
sv_FI@euro/ISO-8859-15 \
|
||||
sv_SE.UTF-8/UTF-8 \
|
||||
sv_SE/ISO-8859-1 \
|
||||
+sv_SE.ISO-8859-15/ISO-8859-15 \
|
||||
sw_KE/UTF-8 \
|
||||
sw_TZ/UTF-8 \
|
||||
szl_PL/UTF-8 \
|
@ -0,0 +1,21 @@
|
||||
Short description: Fedora-specific glibc install locale changes.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-needed
|
||||
|
||||
The Fedora glibc build and install does not need the normal install
|
||||
behaviour which updates the locale archive. The Fedora install phase
|
||||
in the spec file of the rpm will handle this manually.
|
||||
|
||||
diff --git a/localedata/Makefile b/localedata/Makefile
|
||||
index a5f3c92d58954dfc..56719c7c714aa0f1 100644
|
||||
--- a/localedata/Makefile
|
||||
+++ b/localedata/Makefile
|
||||
@@ -218,6 +218,7 @@ $(INSTALL-SUPPORTED-LOCALES): install-locales-dir
|
||||
echo -n '...'; \
|
||||
input=`echo $$locale | sed 's/\([^.]*\)[^@]*\(.*\)/\1\2/'`; \
|
||||
$(LOCALEDEF) $$flags --alias-file=../intl/locale.alias \
|
||||
+ --no-archive \
|
||||
-i locales/$$input -f charmaps/$$charset \
|
||||
$(addprefix --prefix=,$(install_root)) $$locale \
|
||||
&& echo ' done'; \
|
@ -0,0 +1,46 @@
|
||||
Short description: Allow access to internal locale archive functions.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-needed
|
||||
|
||||
This is a part of commit glibc-2.3.3-1492-ga891c7b,
|
||||
needed for fedora/build-locale-archive.c only.
|
||||
|
||||
2007-04-16 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* locale/programs/locarchive.c (add_alias, insert_name): Remove static.
|
||||
|
||||
diff -Nrup a/locale/programs/locarchive.c b/locale/programs/locarchive.c
|
||||
--- a/locale/programs/locarchive.c 2012-06-05 07:42:49.000000000 -0600
|
||||
+++ b/locale/programs/locarchive.c 2012-06-07 12:15:21.585319540 -0600
|
||||
@@ -252,9 +252,9 @@ oldlocrecentcmp (const void *a, const vo
|
||||
/* forward decls for below */
|
||||
static uint32_t add_locale (struct locarhandle *ah, const char *name,
|
||||
locale_data_t data, bool replace);
|
||||
-static void add_alias (struct locarhandle *ah, const char *alias,
|
||||
- bool replace, const char *oldname,
|
||||
- uint32_t *locrec_offset_p);
|
||||
+void add_alias (struct locarhandle *ah, const char *alias,
|
||||
+ bool replace, const char *oldname,
|
||||
+ uint32_t *locrec_offset_p);
|
||||
|
||||
|
||||
static bool
|
||||
@@ -635,7 +635,7 @@ close_archive (struct locarhandle *ah)
|
||||
#include "../../intl/explodename.c"
|
||||
#include "../../intl/l10nflist.c"
|
||||
|
||||
-static struct namehashent *
|
||||
+struct namehashent *
|
||||
insert_name (struct locarhandle *ah,
|
||||
const char *name, size_t name_len, bool replace)
|
||||
{
|
||||
@@ -693,7 +693,7 @@ insert_name (struct locarhandle *ah,
|
||||
return &namehashtab[idx];
|
||||
}
|
||||
|
||||
-static void
|
||||
+void
|
||||
add_alias (struct locarhandle *ah, const char *alias, bool replace,
|
||||
const char *oldname, uint32_t *locrec_offset_p)
|
||||
{
|
@ -0,0 +1,31 @@
|
||||
Short description: Place glibc info into "Libraries" category.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-needed
|
||||
|
||||
The category names for libraries is completely random including
|
||||
"Libraries", "GNU Libraries", "GNU libraries", and "Software libraries."
|
||||
In the GNU info manual the "Software libraries" category is given as an
|
||||
example, but really we need to standardize on a category for upstream.
|
||||
I suggest we drop this change after some upstream discussion.
|
||||
|
||||
From 4820b9175535e13df79ce816106016040014916e Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Jelinek <jakub@redhat.com>
|
||||
Date: Fri, 3 Nov 2006 16:31:21 +0000
|
||||
Subject: [PATCH] Change @dircategory.
|
||||
|
||||
---
|
||||
manual/libc.texinfo | 2 +-
|
||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
--- a/manual/libc.texinfo
|
||||
+++ b/manual/libc.texinfo
|
||||
@@ -7,7 +7,7 @@
|
||||
@include macros.texi
|
||||
|
||||
@comment Tell install-info what to do.
|
||||
-@dircategory Software libraries
|
||||
+@dircategory Libraries
|
||||
@direntry
|
||||
* Libc: (libc). C library.
|
||||
@end direntry
|
@ -0,0 +1,31 @@
|
||||
Short description: Fedora-specific enabling batch read in NSS.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Bug-RHEL: #188246
|
||||
Upstream status: not-submitted
|
||||
|
||||
Enable batch read in NSS. It's not clear if this is always a win or
|
||||
just a win for NIS+, this needs to be analyzed and sent upstream or
|
||||
removed.
|
||||
|
||||
From baba5d9461d4e8a581ac26fe4412ad783ffc73e7 Mon Sep 17 00:00:00 2001
|
||||
From: Jakub Jelinek <jakub@redhat.com>
|
||||
Date: Mon, 1 May 2006 08:02:53 +0000
|
||||
Subject: [PATCH] Enable SETENT_BATCH_READ nis/nss option by default
|
||||
|
||||
* Mon May 1 2006 Jakub Jelinek <jakub@redhat.com> 2.4.90-4
|
||||
- SETENT_BATCH_READ /etc/default/nss option for speeding up
|
||||
some usages of NIS+ (#188246)
|
||||
|
||||
diff --git a/nis/nss b/nis/nss
|
||||
--- a/nis/nss
|
||||
+++ b/nis/nss
|
||||
@@ -25,7 +25,7 @@
|
||||
# memory with every getXXent() call. Otherwise each getXXent() call
|
||||
# might result into a network communication with the server to get
|
||||
# the next entry.
|
||||
-#SETENT_BATCH_READ=TRUE
|
||||
+SETENT_BATCH_READ=TRUE
|
||||
#
|
||||
# ADJUNCT_AS_SHADOW
|
||||
# If set to TRUE, the passwd routines in the NIS NSS module will not
|
@ -0,0 +1,20 @@
|
||||
Short description: NSCD must use nscd user.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-needed
|
||||
|
||||
Fedora-specific configuration adjustment to introduce the nscd user.
|
||||
(Upstream does not assume this user exists.)
|
||||
|
||||
diff -Nrup a/nscd/nscd.conf b/nscd/nscd.conf
|
||||
--- a/nscd/nscd.conf 2012-06-05 07:42:49.000000000 -0600
|
||||
+++ b/nscd/nscd.conf 2012-06-07 12:15:21.818318670 -0600
|
||||
@@ -33,7 +33,7 @@
|
||||
# logfile /var/log/nscd.log
|
||||
# threads 4
|
||||
# max-threads 32
|
||||
-# server-user nobody
|
||||
+ server-user nscd
|
||||
# stat-user somebody
|
||||
debug-level 0
|
||||
# reload-count 5
|
@ -0,0 +1,38 @@
|
||||
Short description: Do not define _XOPEN_STREAMS.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Bug-Fedora: #436349
|
||||
Upstream status: not-submitted
|
||||
|
||||
This patch should go upstream. Not defining _XOPEN_STREAMS is the
|
||||
same as setting it to -1 for POSIX conformance. The headers setting
|
||||
needs to be reviewed indepedently.
|
||||
|
||||
This is part of commit glibc-2.3.3-1564-gd0b6ac6
|
||||
|
||||
* Fri Mar 14 2008 Jakub Jelinek <jakub@redhat.com> 2.7.90-11
|
||||
- remove <stropts.h>, define _XOPEN_STREAMS -1 (#436349)
|
||||
|
||||
diff -Nrup a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
|
||||
--- a/sysdeps/unix/sysv/linux/bits/posix_opt.h 2012-06-05 07:42:49.000000000 -0600
|
||||
+++ b/sysdeps/unix/sysv/linux/bits/posix_opt.h 2012-06-07 12:15:21.817318674 -0600
|
||||
@@ -188,4 +188,7 @@
|
||||
/* Typed memory objects are not available. */
|
||||
#define _POSIX_TYPED_MEMORY_OBJECTS -1
|
||||
|
||||
+/* Streams are not available. */
|
||||
+#define _XOPEN_STREAMS -1
|
||||
+
|
||||
#endif /* bits/posix_opt.h */
|
||||
diff -Nrup a/streams/Makefile b/streams/Makefile
|
||||
--- a/streams/Makefile 2012-06-05 07:42:49.000000000 -0600
|
||||
+++ b/streams/Makefile 2012-06-07 12:15:21.824318649 -0600
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
-headers = stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h
|
||||
+#headers = stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h
|
||||
routines = isastream getmsg getpmsg putmsg putpmsg fattach fdetach
|
||||
|
||||
include ../Rules
|
@ -0,0 +1,21 @@
|
||||
Short description: Provide options to nscd startup.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Upstream status: not-needed
|
||||
|
||||
Fedora-specific nscd startup configuration file.
|
||||
|
||||
diff --git a/nscd/nscd.service b/nscd/nscd.service
|
||||
index b7428a3..19ba185 100644
|
||||
--- a/nscd/nscd.service
|
||||
+++ b/nscd/nscd.service
|
||||
@@ -5,7 +5,8 @@ Description=Name Service Cache Daemon
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
-ExecStart=/usr/sbin/nscd
|
||||
+EnvironmentFile=-/etc/sysconfig/nscd
|
||||
+ExecStart=/usr/sbin/nscd $NSCD_OPTIONS
|
||||
ExecStop=/usr/sbin/nscd --shutdown
|
||||
ExecReload=/usr/sbin/nscd -i passwd
|
||||
ExecReload=/usr/sbin/nscd -i group
|
@ -0,0 +1,40 @@
|
||||
Use python3 for installed executable python scripts.
|
||||
|
||||
Fedora is a Python3-only distribution:
|
||||
https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3
|
||||
|
||||
This fixes build failures where builders may strictly enforce only
|
||||
python3 during a transitional phase.
|
||||
|
||||
Author: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/benchtests/scripts/compare_bench.py b/benchtests/scripts/compare_bench.py
|
||||
index ea25f778c09bba9d..b53beb3c6e32c3cf 100755
|
||||
--- a/benchtests/scripts/compare_bench.py
|
||||
+++ b/benchtests/scripts/compare_bench.py
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/usr/bin/python
|
||||
+#!/usr/bin/python3
|
||||
# Copyright (C) 2015-2018 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
#
|
||||
diff --git a/benchtests/scripts/import_bench.py b/benchtests/scripts/import_bench.py
|
||||
index 602b3f954d4801a6..76bf1528a5418748 100644
|
||||
--- a/benchtests/scripts/import_bench.py
|
||||
+++ b/benchtests/scripts/import_bench.py
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/usr/bin/python
|
||||
+#!/usr/bin/python3
|
||||
# Copyright (C) 2015-2018 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
#
|
||||
diff --git a/benchtests/scripts/validate_benchout.py b/benchtests/scripts/validate_benchout.py
|
||||
index 6147f05bec3a4844..9a5c7947ee4ed7e9 100755
|
||||
--- a/benchtests/scripts/validate_benchout.py
|
||||
+++ b/benchtests/scripts/validate_benchout.py
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/usr/bin/python
|
||||
+#!/usr/bin/python3
|
||||
# Copyright (C) 2014-2018 Free Software Foundation, Inc.
|
||||
# This file is part of the GNU C Library.
|
||||
#
|
@ -0,0 +1,38 @@
|
||||
Short description: Add syslog.target dependency.
|
||||
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
|
||||
Origin: PATCH
|
||||
Bug-Fedora: #1070416
|
||||
Upstream status: not-needed
|
||||
|
||||
Fedora-specific changes to the nscd.service file.
|
||||
See also: glibc-nscd-sysconfig.patch.
|
||||
|
||||
--- a/nscd/nscd.service
|
||||
+++ b/nscd/nscd.service
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
[Unit]
|
||||
Description=Name Service Cache Daemon
|
||||
+After=syslog.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
@@ -17,3 +18,4 @@
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
+Also=nscd.socket
|
||||
diff --git a/nscd/nscd.socket b/nscd/nscd.socket
|
||||
new file mode 100644
|
||||
index 0000000..7e512d5
|
||||
--- /dev/null
|
||||
+++ b/nscd/nscd.socket
|
||||
@@ -0,0 +1,8 @@
|
||||
+[Unit]
|
||||
+Description=Name Service Cache Daemon Socket
|
||||
+
|
||||
+[Socket]
|
||||
+ListenDatagram=/var/run/nscd/socket
|
||||
+
|
||||
+[Install]
|
||||
+WantedBy=sockets.target
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,79 @@
|
||||
commit dbb75513f5cf9285c77c9e55777c5c35b653f890
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 6 07:38:10 2022 +0200
|
||||
|
||||
elf: Rename _dl_sort_maps parameter from skip to force_first
|
||||
|
||||
The new implementation will not be able to skip an arbitrary number
|
||||
of objects.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 99354dc08a010dd3..7a586749adc3fa7d 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -27,12 +27,12 @@
|
||||
If FOR_FINI is true, this is called for finishing an object. */
|
||||
static void
|
||||
_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip, bool for_fini)
|
||||
+ bool force_first, bool for_fini)
|
||||
{
|
||||
/* Allows caller to do the common optimization of skipping the first map,
|
||||
usually the main binary. */
|
||||
- maps += skip;
|
||||
- nmaps -= skip;
|
||||
+ maps += force_first;
|
||||
+ nmaps -= force_first;
|
||||
|
||||
/* A list of one element need not be sorted. */
|
||||
if (nmaps <= 1)
|
||||
@@ -182,7 +182,7 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
|
||||
static void
|
||||
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip __attribute__ ((unused)), bool for_fini)
|
||||
+ bool force_first __attribute__ ((unused)), bool for_fini)
|
||||
{
|
||||
for (int i = nmaps - 1; i >= 0; i--)
|
||||
maps[i]->l_visited = 0;
|
||||
@@ -286,7 +286,7 @@ _dl_sort_maps_init (void)
|
||||
|
||||
void
|
||||
_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip, bool for_fini)
|
||||
+ bool force_first, bool for_fini)
|
||||
{
|
||||
/* It can be tempting to use a static function pointer to store and call
|
||||
the current selected sorting algorithm routine, but experimentation
|
||||
@@ -296,9 +296,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
input cases. A simple if-case with direct function calls appears to
|
||||
be the fastest. */
|
||||
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
- _dl_sort_maps_original (maps, nmaps, skip, for_fini);
|
||||
+ _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
|
||||
else
|
||||
- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
|
||||
+ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
|
||||
}
|
||||
|
||||
#endif /* HAVE_TUNABLES. */
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 9f09a4a280396659..2c1b4c47c6a6c643 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -1056,9 +1056,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
|
||||
initializer functions have completed. */
|
||||
extern void _dl_fini (void) attribute_hidden;
|
||||
|
||||
-/* Sort array MAPS according to dependencies of the contained objects. */
|
||||
+/* Sort array MAPS according to dependencies of the contained objects.
|
||||
+ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
|
||||
+ say otherwise. */
|
||||
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip, bool for_fini) attribute_hidden;
|
||||
+ bool force_first, bool for_fini) attribute_hidden;
|
||||
|
||||
/* The dynamic linker calls this function before and having changing
|
||||
any shared object mappings. The `r_state' member of `struct r_debug'
|
@ -0,0 +1,90 @@
|
||||
commit 1df71d32fe5f5905ffd5d100e5e9ca8ad6210891
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 20 11:00:42 2022 +0200
|
||||
|
||||
elf: Implement force_first handling in _dl_sort_maps_dfs (bug 28937)
|
||||
|
||||
The implementation in _dl_close_worker requires that the first
|
||||
element of l_initfini is always this very map (“We are always the
|
||||
zeroth entry, and since we don't include ourselves in the
|
||||
dependency analysis start at 1.”). Rather than fixing that
|
||||
assumption, this commit adds an implementation of the force_first
|
||||
argument to the new dependency sorting algorithm. This also means
|
||||
that the directly dlopen'ed shared object is always initialized last,
|
||||
which is the least surprising behavior in the presence of cycles.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 7a586749adc3fa7d..6f5c17b47b98fbc7 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
|
||||
static void
|
||||
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
- bool force_first __attribute__ ((unused)), bool for_fini)
|
||||
+ bool force_first, bool for_fini)
|
||||
{
|
||||
+ struct link_map *first_map = maps[0];
|
||||
for (int i = nmaps - 1; i >= 0; i--)
|
||||
maps[i]->l_visited = 0;
|
||||
|
||||
@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
Adjusting the order so that maps[0] is last traversed naturally avoids
|
||||
this problem.
|
||||
|
||||
- Further, the old "optimization" of skipping the main object at maps[0]
|
||||
- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
|
||||
- no longer valid, since traversing along object dependency-links
|
||||
- may "find" the main object even when it is not included in the initial
|
||||
- order (e.g. a dlopen()'ed shared object can have circular dependencies
|
||||
- linked back to itself). In such a case, traversing N-1 objects will
|
||||
- create a N-object result, and raise problems.
|
||||
-
|
||||
To summarize, just passing in the full list, and iterating from back
|
||||
to front makes things much more straightforward. */
|
||||
|
||||
@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
}
|
||||
|
||||
memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
|
||||
+
|
||||
+ /* Skipping the first object at maps[0] is not valid in general,
|
||||
+ since traversing along object dependency-links may "find" that
|
||||
+ first object even when it is not included in the initial order
|
||||
+ (e.g., a dlopen'ed shared object can have circular dependencies
|
||||
+ linked back to itself). In such a case, traversing N-1 objects
|
||||
+ will create a N-object result, and raise problems. Instead,
|
||||
+ force the object back into first place after sorting. This naive
|
||||
+ approach may introduce further dependency ordering violations
|
||||
+ compared to rotating the cycle until the first map is again in
|
||||
+ the first position, but as there is a cycle, at least one
|
||||
+ violation is already present. */
|
||||
+ if (force_first && maps[0] != first_map)
|
||||
+ {
|
||||
+ int i;
|
||||
+ for (i = 0; maps[i] != first_map; ++i)
|
||||
+ ;
|
||||
+ assert (i < nmaps);
|
||||
+ memmove (&maps[1], maps, i * sizeof (maps[0]));
|
||||
+ maps[0] = first_map;
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
|
||||
index 5f7f18ef270bc12d..4bf9052db16fb352 100644
|
||||
--- a/elf/dso-sort-tests-1.def
|
||||
+++ b/elf/dso-sort-tests-1.def
|
||||
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
|
||||
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
|
||||
output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
|
||||
+
|
||||
+# Test that even in the presence of dependency loops involving dlopen'ed
|
||||
+# object, that object is initialized last (and not unloaded prematurely).
|
||||
+# Final destructor order is indeterminate due to the cycle.
|
||||
+tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
|
||||
+output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
|
||||
+output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
|
@ -0,0 +1,35 @@
|
||||
Downstream-specific patch to link DSO sorting tests with -ldl
|
||||
if needed. Upstream does not need this because <dlfcn.h> interfaces
|
||||
are part of libc.
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index 43b5ec4d920ad6a3..ae85e0f4a6ae5b3e 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -657,6 +657,8 @@ def process_testcase(t):
|
||||
% (test_name + "-" + dep + ".FAKE.so",
|
||||
("$(objpfx)" + test_subdir + "/"
|
||||
+ test_name + "-" + dep + ".so")))
|
||||
+ makefile.write(
|
||||
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso)
|
||||
rule = ("$(objpfx)" + test_subdir + "/"
|
||||
+ test_name + "-" + dep + ".FAKE.os: "
|
||||
"$(objpfx)" + test_srcdir
|
||||
@@ -685,6 +687,8 @@ def process_testcase(t):
|
||||
+ test_descr.soname_map[o] + ".so")
|
||||
ldflags += (" -Wl,-soname=" + soname)
|
||||
makefile.write("LDFLAGS-%s = %s\n" % (dso, ldflags))
|
||||
+ makefile.write(
|
||||
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso)
|
||||
if o in test_descr.callrefs:
|
||||
makefile.write("%s-no-z-defs = yes\n" % (dso))
|
||||
|
||||
@@ -702,6 +706,8 @@ def process_testcase(t):
|
||||
+ test_descr.soname_map['#'] + ".so")
|
||||
ldflags += (" -Wl,-soname=" + soname)
|
||||
makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags))
|
||||
+ makefile.write(
|
||||
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % test_name)
|
||||
rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: "
|
||||
"$(objpfx)" + test_srcdir + test_name + ".c\n"
|
||||
"\t$(compile.c) $(OUTPUT_OPTION)\n")
|
@ -0,0 +1,189 @@
|
||||
commit b4bbedb1e75737a80bcc3d53d6eef1fbe0b5f4d5
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Sat Nov 6 14:13:27 2021 -0700
|
||||
|
||||
dso-ordering-test.py: Put all sources in one directory [BZ #28550]
|
||||
|
||||
Put all sources for DSO sorting tests in the dso-sort-tests-src directory
|
||||
and compile test relocatable objects with
|
||||
|
||||
$(objpfx)tst-dso-ordering1-dir/tst-dso-ordering1-a.os: $(objpfx)dso-sort-tests-src/tst-dso-ordering1-a.c
|
||||
$(compile.c) $(OUTPUT_OPTION)
|
||||
|
||||
to avoid random $< values from $(before-compile) when compiling test
|
||||
relocatable objects with
|
||||
|
||||
$(objpfx)%$o: $(objpfx)%.c $(before-compile); $$(compile-command.c)
|
||||
compile-command.c = $(compile.c) $(OUTPUT_OPTION) $(compile-mkdep-flags)
|
||||
compile.c = $(CC) $< -c $(CFLAGS) $(CPPFLAGS)
|
||||
|
||||
for 3 "make -j 28" parallel builds on a machine with 112 cores at the
|
||||
same time.
|
||||
|
||||
This partially fixes BZ #28550.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index 944ee740527d60fd..bde0406be9da14fc 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -526,9 +526,13 @@ def process_testcase(t):
|
||||
base_test_name = t.test_name
|
||||
test_subdir = base_test_name + "-dir"
|
||||
testpfx = objpfx + test_subdir + "/"
|
||||
+ test_srcdir = "dso-sort-tests-src/"
|
||||
+ testpfx_src = objpfx + test_srcdir
|
||||
|
||||
if not os.path.exists(testpfx):
|
||||
os.mkdir(testpfx)
|
||||
+ if not os.path.exists(testpfx_src):
|
||||
+ os.mkdir(testpfx_src)
|
||||
|
||||
def find_objs_not_depended_on(t):
|
||||
objs_not_depended_on = []
|
||||
@@ -595,6 +599,11 @@ def process_testcase(t):
|
||||
# Print out needed Makefile fragments for use in glibc/elf/Makefile.
|
||||
module_names = ""
|
||||
for o in test_descr.objs:
|
||||
+ rule = ("$(objpfx)" + test_subdir + "/" + test_name
|
||||
+ + "-" + o + ".os: $(objpfx)" + test_srcdir
|
||||
+ + test_name + "-" + o + ".c\n"
|
||||
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
+ makefile.write (rule)
|
||||
module_names += " " + test_subdir + "/" + test_name + "-" + o
|
||||
makefile.write("modules-names +=%s\n" % (module_names))
|
||||
|
||||
@@ -637,7 +646,7 @@ def process_testcase(t):
|
||||
# object. This only needs to be done at most once for
|
||||
# an object name.
|
||||
if not dep in fake_created:
|
||||
- f = open(testpfx + test_name + "-" + dep
|
||||
+ f = open(testpfx_src + test_name + "-" + dep
|
||||
+ ".FAKE.c", "w")
|
||||
f.write(" \n")
|
||||
f.close()
|
||||
@@ -648,6 +657,12 @@ def process_testcase(t):
|
||||
% (test_name + "-" + dep + ".FAKE.so",
|
||||
("$(objpfx)" + test_subdir + "/"
|
||||
+ test_name + "-" + dep + ".so")))
|
||||
+ rule = ("$(objpfx)" + test_subdir + "/"
|
||||
+ + test_name + "-" + dep + ".FAKE.os: "
|
||||
+ "$(objpfx)" + test_srcdir
|
||||
+ + test_name + "-" + dep + ".FAKE.c\n"
|
||||
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
+ makefile.write (rule)
|
||||
makefile.write \
|
||||
("modules-names += %s\n"
|
||||
% (test_subdir + "/"
|
||||
@@ -687,6 +702,10 @@ def process_testcase(t):
|
||||
+ test_descr.soname_map['#'] + ".so")
|
||||
ldflags += (" -Wl,-soname=" + soname)
|
||||
makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags))
|
||||
+ rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: "
|
||||
+ "$(objpfx)" + test_srcdir + test_name + ".c\n"
|
||||
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
+ makefile.write (rule)
|
||||
|
||||
not_depended_objs = find_objs_not_depended_on(test_descr)
|
||||
if not_depended_objs:
|
||||
@@ -745,7 +764,7 @@ def process_testcase(t):
|
||||
" something_failed=true\n"
|
||||
"else\n"
|
||||
" diff -wu ${common_objpfx}elf/%s/%s%s.output \\\n"
|
||||
- " ${common_objpfx}elf/%s/%s%s.exp\n"
|
||||
+ " ${common_objpfx}elf/%s%s%s.exp\n"
|
||||
" if [ $? -ne 0 ]; then\n"
|
||||
" echo '%sFAIL: %s%s expected output comparison'\n"
|
||||
" something_failed=true\n"
|
||||
@@ -753,14 +772,14 @@ def process_testcase(t):
|
||||
"fi\n"
|
||||
% (("X" if xfail else ""), test_name, tunable_descr,
|
||||
test_subdir, test_name, tunable_sfx,
|
||||
- test_subdir, base_test_name, exp_tunable_sfx,
|
||||
+ test_srcdir, base_test_name, exp_tunable_sfx,
|
||||
("X" if xfail else ""), test_name, tunable_descr))
|
||||
|
||||
# Generate C files according to dependency and calling relations from
|
||||
# description string.
|
||||
for obj in test_descr.objs:
|
||||
src_name = test_name + "-" + obj + ".c"
|
||||
- f = open(testpfx + src_name, "w")
|
||||
+ f = open(testpfx_src + src_name, "w")
|
||||
if obj in test_descr.callrefs:
|
||||
called_objs = test_descr.callrefs[obj]
|
||||
for callee in called_objs:
|
||||
@@ -804,7 +823,7 @@ def process_testcase(t):
|
||||
f.close()
|
||||
|
||||
# Open C file for writing main program
|
||||
- f = open(testpfx + test_name + ".c", "w")
|
||||
+ f = open(testpfx_src + test_name + ".c", "w")
|
||||
|
||||
# if there are some operations in main(), it means we need -ldl
|
||||
f.write("#include <stdio.h>\n")
|
||||
@@ -885,7 +904,7 @@ def process_testcase(t):
|
||||
for obj in test_descr.objs:
|
||||
src_name = test_name + "-" + obj + ".c"
|
||||
obj_name = test_name + "-" + obj + ".os"
|
||||
- run_cmd([build_gcc, "-c", "-fPIC", testpfx + src_name,
|
||||
+ run_cmd([build_gcc, "-c", "-fPIC", testpfx_src + src_name,
|
||||
"-o", testpfx + obj_name])
|
||||
|
||||
obj_processed = {}
|
||||
@@ -903,10 +922,12 @@ def process_testcase(t):
|
||||
deps.append(dep + ".FAKE")
|
||||
if not dep in fake_created:
|
||||
base_name = testpfx + test_name + "-" + dep
|
||||
+ src_base_name = (testpfx_src + test_name
|
||||
+ + "-" + dep)
|
||||
cmd = [build_gcc, "-Wl,--no-as-needed",
|
||||
("-Wl,-soname=" + base_name + ".so"),
|
||||
"-shared", base_name + ".FAKE.c",
|
||||
- "-o", base_name + ".FAKE.so"]
|
||||
+ "-o", src_base_name + ".FAKE.so"]
|
||||
run_cmd(cmd)
|
||||
fake_created[dep] = True
|
||||
dso_deps = map(lambda d: testpfx + test_name + "-" + d + ".so",
|
||||
@@ -932,7 +953,7 @@ def process_testcase(t):
|
||||
main_deps = map(lambda d: testpfx + test_name + "-" + d + ".so",
|
||||
deps)
|
||||
cmd = [build_gcc, "-Wl,--no-as-needed", "-o", testpfx + test_name,
|
||||
- testpfx + test_name + ".c", "-L%s" % (os.getcwd()),
|
||||
+ testpfx_src + test_name + ".c", "-L%s" % (os.getcwd()),
|
||||
"-Wl,-rpath-link=%s" % (os.getcwd())]
|
||||
if '#' in test_descr.soname_map:
|
||||
soname = ("-Wl,-soname=" + testpfx + test_name + "-"
|
||||
@@ -987,14 +1008,14 @@ def process_testcase(t):
|
||||
sfx = ""
|
||||
if r[0] != "":
|
||||
sfx = "-" + r[0].replace("=","_")
|
||||
- f = open(testpfx + t.test_name + sfx + ".exp", "w")
|
||||
+ f = open(testpfx_src + t.test_name + sfx + ".exp", "w")
|
||||
(output, xfail) = r[1]
|
||||
f.write('%s' % output)
|
||||
f.close()
|
||||
|
||||
# Create header part of top-level testcase shell script, to wrap execution
|
||||
# and output comparison together.
|
||||
- t.sh = open(testpfx + t.test_name + ".sh", "w")
|
||||
+ t.sh = open(testpfx_src + t.test_name + ".sh", "w")
|
||||
t.sh.write("#!/bin/sh\n")
|
||||
t.sh.write("# Test driver for %s, generated by "
|
||||
"dso-ordering-test.py\n" % (t.test_name))
|
||||
@@ -1022,12 +1043,12 @@ def process_testcase(t):
|
||||
sfx = ""
|
||||
if r[0] != "":
|
||||
sfx = "-" + r[0].replace("=","_")
|
||||
- expected_output_files += " $(objpfx)%s/%s%s.exp" % (test_subdir,
|
||||
+ expected_output_files += " $(objpfx)%s%s%s.exp" % (test_srcdir,
|
||||
t.test_name, sfx)
|
||||
makefile.write \
|
||||
- ("$(objpfx)%s.out: $(objpfx)%s/%s.sh%s "
|
||||
+ ("$(objpfx)%s.out: $(objpfx)%s%s.sh%s "
|
||||
"$(common-objpfx)support/test-run-command\n"
|
||||
- % (t.test_name, test_subdir, t.test_name,
|
||||
+ % (t.test_name, test_srcdir, t.test_name,
|
||||
expected_output_files))
|
||||
makefile.write("\t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' "
|
||||
"'$(run-program-env)' > $@; $(evaluate-test)\n")
|
@ -0,0 +1,589 @@
|
||||
commit 15a0c5730d1d5aeb95f50c9ec7470640084feae8
|
||||
Author: Chung-Lin Tang <cltang@codesourcery.com>
|
||||
Date: Thu Oct 21 21:41:22 2021 +0800
|
||||
|
||||
elf: Fix slow DSO sorting behavior in dynamic loader (BZ #17645)
|
||||
|
||||
This second patch contains the actual implementation of a new sorting algorithm
|
||||
for shared objects in the dynamic loader, which solves the slow behavior that
|
||||
the current "old" algorithm falls into when the DSO set contains circular
|
||||
dependencies.
|
||||
|
||||
The new algorithm implemented here is simply depth-first search (DFS) to obtain
|
||||
the Reverse-Post Order (RPO) sequence, a topological sort. A new l_visited:1
|
||||
bitfield is added to struct link_map to more elegantly facilitate such a search.
|
||||
|
||||
The DFS algorithm is applied to the input maps[nmap-1] backwards towards
|
||||
maps[0]. This has the effect of a more "shallow" recursion depth in general
|
||||
since the input is in BFS. Also, when combined with the natural order of
|
||||
processing l_initfini[] at each node, this creates a resulting output sorting
|
||||
closer to the intuitive "left-to-right" order in most cases.
|
||||
|
||||
Another notable implementation adjustment related to this _dl_sort_maps change
|
||||
is the removing of two char arrays 'used' and 'done' in _dl_close_worker to
|
||||
represent two per-map attributes. This has been changed to simply use two new
|
||||
bit-fields l_map_used:1, l_map_done:1 added to struct link_map. This also allows
|
||||
discarding the clunky 'used' array sorting that _dl_sort_maps had to sometimes
|
||||
do along the way.
|
||||
|
||||
Tunable support for switching between different sorting algorithms at runtime is
|
||||
also added. A new tunable 'glibc.rtld.dynamic_sort' with current valid values 1
|
||||
(old algorithm) and 2 (new DFS algorithm) has been added. At time of commit
|
||||
of this patch, the default setting is 1 (old algorithm).
|
||||
|
||||
Signed-off-by: Chung-Lin Tang <cltang@codesourcery.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
elf/dl-tunables.list
|
||||
(No mem.tagging tunable downstream.)
|
||||
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index 74ca9a85dd309780..22225efb3226c3e1 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -167,8 +167,6 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
|
||||
bool any_tls = false;
|
||||
const unsigned int nloaded = ns->_ns_nloaded;
|
||||
- char used[nloaded];
|
||||
- char done[nloaded];
|
||||
struct link_map *maps[nloaded];
|
||||
|
||||
/* Run over the list and assign indexes to the link maps and enter
|
||||
@@ -176,24 +174,21 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
int idx = 0;
|
||||
for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
|
||||
{
|
||||
+ l->l_map_used = 0;
|
||||
+ l->l_map_done = 0;
|
||||
l->l_idx = idx;
|
||||
maps[idx] = l;
|
||||
++idx;
|
||||
-
|
||||
}
|
||||
assert (idx == nloaded);
|
||||
|
||||
- /* Prepare the bitmaps. */
|
||||
- memset (used, '\0', sizeof (used));
|
||||
- memset (done, '\0', sizeof (done));
|
||||
-
|
||||
/* Keep track of the lowest index link map we have covered already. */
|
||||
int done_index = -1;
|
||||
while (++done_index < nloaded)
|
||||
{
|
||||
struct link_map *l = maps[done_index];
|
||||
|
||||
- if (done[done_index])
|
||||
+ if (l->l_map_done)
|
||||
/* Already handled. */
|
||||
continue;
|
||||
|
||||
@@ -204,12 +199,12 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
|
||||
acquire is sufficient and correct. */
|
||||
&& atomic_load_acquire (&l->l_tls_dtor_count) == 0
|
||||
- && !used[done_index])
|
||||
+ && !l->l_map_used)
|
||||
continue;
|
||||
|
||||
/* We need this object and we handle it now. */
|
||||
- done[done_index] = 1;
|
||||
- used[done_index] = 1;
|
||||
+ l->l_map_used = 1;
|
||||
+ l->l_map_done = 1;
|
||||
/* Signal the object is still needed. */
|
||||
l->l_idx = IDX_STILL_USED;
|
||||
|
||||
@@ -225,9 +220,9 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
{
|
||||
assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
|
||||
|
||||
- if (!used[(*lp)->l_idx])
|
||||
+ if (!(*lp)->l_map_used)
|
||||
{
|
||||
- used[(*lp)->l_idx] = 1;
|
||||
+ (*lp)->l_map_used = 1;
|
||||
/* If we marked a new object as used, and we've
|
||||
already processed it, then we need to go back
|
||||
and process again from that point forward to
|
||||
@@ -250,9 +245,9 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
{
|
||||
assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
|
||||
|
||||
- if (!used[jmap->l_idx])
|
||||
+ if (!jmap->l_map_used)
|
||||
{
|
||||
- used[jmap->l_idx] = 1;
|
||||
+ jmap->l_map_used = 1;
|
||||
if (jmap->l_idx - 1 < done_index)
|
||||
done_index = jmap->l_idx - 1;
|
||||
}
|
||||
@@ -262,8 +257,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
|
||||
/* Sort the entries. We can skip looking for the binary itself which is
|
||||
at the front of the search list for the main namespace. */
|
||||
- _dl_sort_maps (maps + (nsid == LM_ID_BASE), nloaded - (nsid == LM_ID_BASE),
|
||||
- used + (nsid == LM_ID_BASE), true);
|
||||
+ _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true);
|
||||
|
||||
/* Call all termination functions at once. */
|
||||
bool unload_any = false;
|
||||
@@ -277,7 +271,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* All elements must be in the same namespace. */
|
||||
assert (imap->l_ns == nsid);
|
||||
|
||||
- if (!used[i])
|
||||
+ if (!imap->l_map_used)
|
||||
{
|
||||
assert (imap->l_type == lt_loaded && !imap->l_nodelete_active);
|
||||
|
||||
@@ -315,7 +309,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
if (i < first_loaded)
|
||||
first_loaded = i;
|
||||
}
|
||||
- /* Else used[i]. */
|
||||
+ /* Else imap->l_map_used. */
|
||||
else if (imap->l_type == lt_loaded)
|
||||
{
|
||||
struct r_scope_elem *new_list = NULL;
|
||||
@@ -524,7 +518,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
for (unsigned int i = first_loaded; i < nloaded; ++i)
|
||||
{
|
||||
struct link_map *imap = maps[i];
|
||||
- if (!used[i])
|
||||
+ if (!imap->l_map_used)
|
||||
{
|
||||
assert (imap->l_type == lt_loaded);
|
||||
|
||||
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
|
||||
index 007069f670eced95..9365d54c8e03e5f4 100644
|
||||
--- a/elf/dl-deps.c
|
||||
+++ b/elf/dl-deps.c
|
||||
@@ -612,10 +612,9 @@ Filters not supported with LD_TRACE_PRELINKING"));
|
||||
|
||||
/* If libc.so.6 is the main map, it participates in the sort, so
|
||||
that the relocation order is correct regarding libc.so.6. */
|
||||
- if (l_initfini[0] == GL (dl_ns)[l_initfini[0]->l_ns].libc_map)
|
||||
- _dl_sort_maps (l_initfini, nlist, NULL, false);
|
||||
- else
|
||||
- _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
|
||||
+ _dl_sort_maps (l_initfini, nlist,
|
||||
+ (l_initfini[0] != GL (dl_ns)[l_initfini[0]->l_ns].libc_map),
|
||||
+ false);
|
||||
|
||||
/* Terminate the list of dependencies. */
|
||||
l_initfini[nlist] = NULL;
|
||||
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
|
||||
index eea9d8aad736a99e..e14259a3c8806e0d 100644
|
||||
--- a/elf/dl-fini.c
|
||||
+++ b/elf/dl-fini.c
|
||||
@@ -95,8 +95,7 @@ _dl_fini (void)
|
||||
/* Now we have to do the sorting. We can skip looking for the
|
||||
binary itself which is at the front of the search list for
|
||||
the main namespace. */
|
||||
- _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE),
|
||||
- NULL, true);
|
||||
+ _dl_sort_maps (maps, nmaps, (ns == LM_ID_BASE), true);
|
||||
|
||||
/* We do not rely on the linked list of loaded object anymore
|
||||
from this point on. We have our own list here (maps). The
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index b2a01ede627be1e9..398a08f28c4d9ff1 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -16,16 +16,24 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
+#include <assert.h>
|
||||
#include <ldsodefs.h>
|
||||
+#include <elf/dl-tunables.h>
|
||||
|
||||
+/* Note: this is the older, "original" sorting algorithm, being used as
|
||||
+ default up to 2.35.
|
||||
|
||||
-/* Sort array MAPS according to dependencies of the contained objects.
|
||||
- Array USED, if non-NULL, is permutated along MAPS. If FOR_FINI this is
|
||||
- called for finishing an object. */
|
||||
-void
|
||||
-_dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
- bool for_fini)
|
||||
+ Sort array MAPS according to dependencies of the contained objects.
|
||||
+ If FOR_FINI is true, this is called for finishing an object. */
|
||||
+static void
|
||||
+_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
|
||||
+ unsigned int skip, bool for_fini)
|
||||
{
|
||||
+ /* Allows caller to do the common optimization of skipping the first map,
|
||||
+ usually the main binary. */
|
||||
+ maps += skip;
|
||||
+ nmaps -= skip;
|
||||
+
|
||||
/* A list of one element need not be sorted. */
|
||||
if (nmaps <= 1)
|
||||
return;
|
||||
@@ -66,14 +74,6 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
(k - i) * sizeof (maps[0]));
|
||||
maps[k] = thisp;
|
||||
|
||||
- if (used != NULL)
|
||||
- {
|
||||
- char here_used = used[i];
|
||||
- memmove (&used[i], &used[i + 1],
|
||||
- (k - i) * sizeof (used[0]));
|
||||
- used[k] = here_used;
|
||||
- }
|
||||
-
|
||||
if (seen[i + 1] > nmaps - i)
|
||||
{
|
||||
++i;
|
||||
@@ -120,3 +120,183 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
next:;
|
||||
}
|
||||
}
|
||||
+
|
||||
+#if !HAVE_TUNABLES
|
||||
+/* In this case, just default to the original algorithm. */
|
||||
+strong_alias (_dl_sort_maps_original, _dl_sort_maps);
|
||||
+#else
|
||||
+
|
||||
+/* We use a recursive function due to its better clarity and ease of
|
||||
+ implementation, as well as faster execution speed. We already use
|
||||
+ alloca() for list allocation during the breadth-first search of
|
||||
+ dependencies in _dl_map_object_deps(), and this should be on the
|
||||
+ same order of worst-case stack usage.
|
||||
+
|
||||
+ Note: the '*rpo' parameter is supposed to point to one past the
|
||||
+ last element of the array where we save the sort results, and is
|
||||
+ decremented before storing the current map at each level. */
|
||||
+
|
||||
+static void
|
||||
+dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
+ bool *do_reldeps)
|
||||
+{
|
||||
+ if (map->l_visited)
|
||||
+ return;
|
||||
+
|
||||
+ map->l_visited = 1;
|
||||
+
|
||||
+ if (map->l_initfini)
|
||||
+ {
|
||||
+ for (int i = 0; map->l_initfini[i] != NULL; i++)
|
||||
+ {
|
||||
+ struct link_map *dep = map->l_initfini[i];
|
||||
+ if (dep->l_visited == 0
|
||||
+ && dep->l_main_map == 0)
|
||||
+ dfs_traversal (rpo, dep, do_reldeps);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (__glibc_unlikely (do_reldeps != NULL && map->l_reldeps != NULL))
|
||||
+ {
|
||||
+ /* Indicate that we encountered relocation dependencies during
|
||||
+ traversal. */
|
||||
+ *do_reldeps = true;
|
||||
+
|
||||
+ for (int m = map->l_reldeps->act - 1; m >= 0; m--)
|
||||
+ {
|
||||
+ struct link_map *dep = map->l_reldeps->list[m];
|
||||
+ if (dep->l_visited == 0
|
||||
+ && dep->l_main_map == 0)
|
||||
+ dfs_traversal (rpo, dep, do_reldeps);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ *rpo -= 1;
|
||||
+ **rpo = map;
|
||||
+}
|
||||
+
|
||||
+/* Topologically sort array MAPS according to dependencies of the contained
|
||||
+ objects. */
|
||||
+
|
||||
+static void
|
||||
+_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
+ unsigned int skip __attribute__ ((unused)), bool for_fini)
|
||||
+{
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ maps[i]->l_visited = 0;
|
||||
+
|
||||
+ /* We apply DFS traversal for each of maps[i] until the whole total order
|
||||
+ is found and we're at the start of the Reverse-Postorder (RPO) sequence,
|
||||
+ which is a topological sort.
|
||||
+
|
||||
+ We go from maps[nmaps - 1] backwards towards maps[0] at this level.
|
||||
+ Due to the breadth-first search (BFS) ordering we receive, going
|
||||
+ backwards usually gives a more shallow depth-first recursion depth,
|
||||
+ adding more stack usage safety. Also, combined with the natural
|
||||
+ processing order of l_initfini[] at each node during DFS, this maintains
|
||||
+ an ordering closer to the original link ordering in the sorting results
|
||||
+ under most simpler cases.
|
||||
+
|
||||
+ Another reason we order the top level backwards, it that maps[0] is
|
||||
+ usually exactly the main object of which we're in the midst of
|
||||
+ _dl_map_object_deps() processing, and maps[0]->l_initfini[] is still
|
||||
+ blank. If we start the traversal from maps[0], since having no
|
||||
+ dependencies yet filled in, maps[0] will always be immediately
|
||||
+ incorrectly placed at the last place in the order (first in reverse).
|
||||
+ Adjusting the order so that maps[0] is last traversed naturally avoids
|
||||
+ this problem.
|
||||
+
|
||||
+ Further, the old "optimization" of skipping the main object at maps[0]
|
||||
+ from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
|
||||
+ no longer valid, since traversing along object dependency-links
|
||||
+ may "find" the main object even when it is not included in the initial
|
||||
+ order (e.g. a dlopen()'ed shared object can have circular dependencies
|
||||
+ linked back to itself). In such a case, traversing N-1 objects will
|
||||
+ create a N-object result, and raise problems.
|
||||
+
|
||||
+ To summarize, just passing in the full list, and iterating from back
|
||||
+ to front makes things much more straightforward. */
|
||||
+
|
||||
+ /* Array to hold RPO sorting results, before we copy back to maps[]. */
|
||||
+ struct link_map *rpo[nmaps];
|
||||
+
|
||||
+ /* The 'head' position during each DFS iteration. Note that we start at
|
||||
+ one past the last element due to first-decrement-then-store (see the
|
||||
+ bottom of above dfs_traversal() routine). */
|
||||
+ struct link_map **rpo_head = &rpo[nmaps];
|
||||
+
|
||||
+ bool do_reldeps = false;
|
||||
+ bool *do_reldeps_ref = (for_fini ? &do_reldeps : NULL);
|
||||
+
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ {
|
||||
+ dfs_traversal (&rpo_head, maps[i], do_reldeps_ref);
|
||||
+
|
||||
+ /* We can break early if all objects are already placed. */
|
||||
+ if (rpo_head == rpo)
|
||||
+ goto end;
|
||||
+ }
|
||||
+ assert (rpo_head == rpo);
|
||||
+
|
||||
+ end:
|
||||
+ /* Here we may do a second pass of sorting, using only l_initfini[]
|
||||
+ static dependency links. This is avoided if !FOR_FINI or if we didn't
|
||||
+ find any reldeps in the first DFS traversal.
|
||||
+
|
||||
+ The reason we do this is: while it is unspecified how circular
|
||||
+ dependencies should be handled, the presumed reasonable behavior is to
|
||||
+ have destructors to respect static dependency links as much as possible,
|
||||
+ overriding reldeps if needed. And the first sorting pass, which takes
|
||||
+ l_initfini/l_reldeps links equally, may not preserve this priority.
|
||||
+
|
||||
+ Hence we do a 2nd sorting pass, taking only DT_NEEDED links into account
|
||||
+ (see how the do_reldeps argument to dfs_traversal() is NULL below). */
|
||||
+ if (do_reldeps)
|
||||
+ {
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ rpo[i]->l_visited = 0;
|
||||
+
|
||||
+ struct link_map **maps_head = &maps[nmaps];
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ {
|
||||
+ dfs_traversal (&maps_head, rpo[i], NULL);
|
||||
+
|
||||
+ /* We can break early if all objects are already placed.
|
||||
+ The below memcpy is not needed in the do_reldeps case here,
|
||||
+ since we wrote back to maps[] during DFS traversal. */
|
||||
+ if (maps_head == maps)
|
||||
+ return;
|
||||
+ }
|
||||
+ assert (maps_head == maps);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+_dl_sort_maps_init (void)
|
||||
+{
|
||||
+ int32_t algorithm = TUNABLE_GET (glibc, rtld, dynamic_sort, int32_t, NULL);
|
||||
+ GLRO(dl_dso_sort_algo) = algorithm == 1 ? dso_sort_algorithm_original
|
||||
+ : dso_sort_algorithm_dfs;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
+ unsigned int skip, bool for_fini)
|
||||
+{
|
||||
+ /* It can be tempting to use a static function pointer to store and call
|
||||
+ the current selected sorting algorithm routine, but experimentation
|
||||
+ shows that current processors still do not handle indirect branches
|
||||
+ that efficiently, plus a static function pointer will involve
|
||||
+ PTR_MANGLE/DEMANGLE, further impairing performance of small, common
|
||||
+ input cases. A simple if-case with direct function calls appears to
|
||||
+ be the fastest. */
|
||||
+ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
+ _dl_sort_maps_original (maps, nmaps, skip, for_fini);
|
||||
+ else
|
||||
+ _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
|
||||
+}
|
||||
+
|
||||
+#endif /* HAVE_TUNABLES. */
|
||||
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||
index e9943e889ef447ad..ae03aec9764e29d3 100644
|
||||
--- a/elf/dl-support.c
|
||||
+++ b/elf/dl-support.c
|
||||
@@ -155,6 +155,8 @@ size_t _dl_phnum;
|
||||
uint64_t _dl_hwcap __attribute__ ((nocommon));
|
||||
uint64_t _dl_hwcap2 __attribute__ ((nocommon));
|
||||
|
||||
+enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
+
|
||||
/* The value of the FPU control word the kernel will preset in hardware. */
|
||||
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
|
||||
|
||||
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
|
||||
index 998c5d52bcab8193..4e8a986541fc4c09 100644
|
||||
--- a/elf/dl-sysdep.c
|
||||
+++ b/elf/dl-sysdep.c
|
||||
@@ -223,6 +223,9 @@ _dl_sysdep_start (void **start_argptr,
|
||||
|
||||
__tunables_init (_environ);
|
||||
|
||||
+ /* Initialize DSO sorting algorithm after tunables. */
|
||||
+ _dl_sort_maps_init ();
|
||||
+
|
||||
#ifdef DL_SYSDEP_INIT
|
||||
DL_SYSDEP_INIT;
|
||||
#endif
|
||||
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
|
||||
index 6408a8e5ae92d2c6..54ef2a921310b229 100644
|
||||
--- a/elf/dl-tunables.list
|
||||
+++ b/elf/dl-tunables.list
|
||||
@@ -140,4 +140,13 @@ glibc {
|
||||
default: 512
|
||||
}
|
||||
}
|
||||
+
|
||||
+ rtld {
|
||||
+ dynamic_sort {
|
||||
+ type: INT_32
|
||||
+ minval: 1
|
||||
+ maxval: 2
|
||||
+ default: 1
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
|
||||
index 873ddf55d91155c6..5f7f18ef270bc12d 100644
|
||||
--- a/elf/dso-sort-tests-1.def
|
||||
+++ b/elf/dso-sort-tests-1.def
|
||||
@@ -62,5 +62,5 @@ output: b>a>{}<a<b
|
||||
# The below expected outputs are what the two algorithms currently produce
|
||||
# respectively, for regression testing purposes.
|
||||
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
|
||||
-xfail_output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
+output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index b47e84ca2fb6f03c..cd2cc4024a3581c2 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -1453,6 +1453,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
main_map->l_name = (char *) "";
|
||||
*user_entry = main_map->l_entry;
|
||||
|
||||
+ /* Set bit indicating this is the main program map. */
|
||||
+ main_map->l_main_map = 1;
|
||||
+
|
||||
#ifdef HAVE_AUX_VECTOR
|
||||
/* Adjust the on-stack auxiliary vector so that it looks like the
|
||||
binary was executed directly. */
|
||||
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
|
||||
index 4f3f7ee4e30a2b42..118afc271057afd4 100644
|
||||
--- a/elf/tst-rtld-list-tunables.exp
|
||||
+++ b/elf/tst-rtld-list-tunables.exp
|
||||
@@ -10,5 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
+glibc.rtld.dynamic_sort: 1 (min: 1, max: 2)
|
||||
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
|
||||
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index dd491989beb41353..041ff5f753a9ee11 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -181,6 +181,11 @@ struct link_map
|
||||
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
|
||||
unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
|
||||
unsigned int l_reserved:2; /* Reserved for internal use. */
|
||||
+ unsigned int l_main_map:1; /* Nonzero for the map of the main program. */
|
||||
+ unsigned int l_visited:1; /* Used internally for map dependency
|
||||
+ graph traversal. */
|
||||
+ unsigned int l_map_used:1; /* These two bits are used during traversal */
|
||||
+ unsigned int l_map_done:1; /* of maps in _dl_close_worker. */
|
||||
unsigned int l_phdr_allocated:1; /* Nonzero if the data structure pointed
|
||||
to by `l_phdr' is allocated. */
|
||||
unsigned int l_soname_added:1; /* Nonzero if the SONAME is for sure in
|
||||
diff --git a/manual/tunables.texi b/manual/tunables.texi
|
||||
index 43272cf885d1e3e6..c3f96cdc85208926 100644
|
||||
--- a/manual/tunables.texi
|
||||
+++ b/manual/tunables.texi
|
||||
@@ -303,6 +303,17 @@ changed once allocated at process startup. The default allocation of
|
||||
optional static TLS is 512 bytes and is allocated in every thread.
|
||||
@end deftp
|
||||
|
||||
+@deftp Tunable glibc.rtld.dynamic_sort
|
||||
+Sets the algorithm to use for DSO sorting, valid values are @samp{1} and
|
||||
+@samp{2}. For value of @samp{1}, an older O(n^3) algorithm is used, which is
|
||||
+long time tested, but may have performance issues when dependencies between
|
||||
+shared objects contain cycles due to circular dependencies. When set to the
|
||||
+value of @samp{2}, a different algorithm is used, which implements a
|
||||
+topological sort through depth-first search, and does not exhibit the
|
||||
+performance issues of @samp{1}.
|
||||
+
|
||||
+The default value of this tunable is @samp{1}.
|
||||
+@end deftp
|
||||
|
||||
@node Elision Tunables
|
||||
@section Elision Tunables
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 5e56550a4d556fa7..9f09a4a280396659 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -240,6 +240,13 @@ enum allowmask
|
||||
};
|
||||
|
||||
|
||||
+/* DSO sort algorithm to use (check dl-sort-maps.c). */
|
||||
+enum dso_sort_algorithm
|
||||
+ {
|
||||
+ dso_sort_algorithm_original,
|
||||
+ dso_sort_algorithm_dfs
|
||||
+ };
|
||||
+
|
||||
struct audit_ifaces
|
||||
{
|
||||
void (*activity) (uintptr_t *, unsigned int);
|
||||
@@ -633,6 +640,8 @@ struct rtld_global_ro
|
||||
platforms. */
|
||||
EXTERN uint64_t _dl_hwcap2;
|
||||
|
||||
+ EXTERN enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
+
|
||||
#ifdef SHARED
|
||||
/* We add a function table to _rtld_global which is then used to
|
||||
call the function instead of going through the PLT. The result
|
||||
@@ -1049,7 +1058,7 @@ extern void _dl_fini (void) attribute_hidden;
|
||||
|
||||
/* Sort array MAPS according to dependencies of the contained objects. */
|
||||
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
- char *used, bool for_fini) attribute_hidden;
|
||||
+ unsigned int skip, bool for_fini) attribute_hidden;
|
||||
|
||||
/* The dynamic linker calls this function before and having changing
|
||||
any shared object mappings. The `r_state' member of `struct r_debug'
|
||||
@@ -1167,6 +1176,9 @@ extern struct link_map * _dl_get_dl_main_map (void)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
+/* Initialize the DSO sort algorithm to use. */
|
||||
+extern void _dl_sort_maps_init (void) attribute_hidden;
|
||||
+
|
||||
/* Initialization of libpthread for statically linked applications.
|
||||
If libpthread is not linked in, this is an empty function. */
|
||||
void __pthread_initialize_minimal (void) weak_function;
|
@ -0,0 +1,25 @@
|
||||
commit d3bf2f5927d51258a51ac7fde04f4805f8ee294a
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Wed Nov 3 09:19:30 2021 -0300
|
||||
|
||||
elf: Do not run DSO sorting if tunables is not enabled
|
||||
|
||||
Since the argorithm selection requires tunables.
|
||||
|
||||
Checked on x86_64-linux-gnu with --enable-tunables=no.
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index e92f62f279566684..3b5e1f59e6696a2b 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -998,8 +998,10 @@ include $(objpfx)$(1).generated-makefile
|
||||
endef
|
||||
|
||||
# Generate from each testcase description file
|
||||
+ifeq (yes,$(have-tunables))
|
||||
$(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
|
||||
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
|
||||
+endif
|
||||
|
||||
check-abi: $(objpfx)check-abi-ld.out
|
||||
tests-special += $(objpfx)check-abi-ld.out
|
@ -0,0 +1,45 @@
|
||||
commit 1f67d8286b5da9266a138198ef1f15c27cbb0010
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Mon Nov 15 16:28:39 2021 -0800
|
||||
|
||||
elf: Use a temporary file to generate Makefile fragments [BZ #28550]
|
||||
|
||||
1. Use a temporary file to generate Makefile fragments for DSO sorting
|
||||
tests and use -include on them.
|
||||
2. Add Makefile fragments to postclean-generated so that a "make clean"
|
||||
removes the autogenerated fragments and a subsequent "make" regenerates
|
||||
them.
|
||||
|
||||
This partially fixes BZ #28550.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 3b5e1f59e6696a2b..22a8060f7d3bb1a1 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -986,6 +986,7 @@ tests-special += \
|
||||
# tests-special
|
||||
endif
|
||||
|
||||
+ifndef avoid-generated
|
||||
# DSO sorting tests:
|
||||
# The dso-ordering-test.py script generates testcase source files in $(objpfx),
|
||||
# creating a $(objpfx)<testcase-name>-dir for each testcase, and creates a
|
||||
@@ -993,9 +994,14 @@ endif
|
||||
define include_dsosort_tests
|
||||
$(objpfx)$(1).generated-makefile: $(1)
|
||||
$(PYTHON) $(..)scripts/dso-ordering-test.py \
|
||||
- --description-file $$< --objpfx $(objpfx) --output-makefile $$@
|
||||
-include $(objpfx)$(1).generated-makefile
|
||||
+ --description-file $$< --objpfx $(objpfx) --output-makefile $$@T
|
||||
+ mv $$@T $$@
|
||||
+-include $(objpfx)$(1).generated-makefile
|
||||
endef
|
||||
+endif
|
||||
+
|
||||
+postclean-generated += $(objpfx)/dso-sort-tests-2.generated-makefile \
|
||||
+ $(objpfx)/dso-sort-tests-2.generated-makefile
|
||||
|
||||
# Generate from each testcase description file
|
||||
ifeq (yes,$(have-tunables))
|
@ -0,0 +1,49 @@
|
||||
commit 0884724a95b60452ad483dbe086d237d02ba624d
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Dec 14 12:37:44 2021 +0100
|
||||
|
||||
elf: Use new dependency sorting algorithm by default
|
||||
|
||||
The default has to change eventually, and there are no known failures
|
||||
that require a delay.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
|
||||
index 54ef2a921310b229..f11ca5b3e8b09b43 100644
|
||||
--- a/elf/dl-tunables.list
|
||||
+++ b/elf/dl-tunables.list
|
||||
@@ -146,7 +146,7 @@ glibc {
|
||||
type: INT_32
|
||||
minval: 1
|
||||
maxval: 2
|
||||
- default: 1
|
||||
+ default: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
|
||||
index 118afc271057afd4..478ee8ab091685eb 100644
|
||||
--- a/elf/tst-rtld-list-tunables.exp
|
||||
+++ b/elf/tst-rtld-list-tunables.exp
|
||||
@@ -10,6 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
-glibc.rtld.dynamic_sort: 1 (min: 1, max: 2)
|
||||
+glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
|
||||
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
|
||||
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
|
||||
diff --git a/manual/tunables.texi b/manual/tunables.texi
|
||||
index c3f96cdc85208926..7b70e80391ee87f7 100644
|
||||
--- a/manual/tunables.texi
|
||||
+++ b/manual/tunables.texi
|
||||
@@ -312,7 +312,7 @@ value of @samp{2}, a different algorithm is used, which implements a
|
||||
topological sort through depth-first search, and does not exhibit the
|
||||
performance issues of @samp{1}.
|
||||
|
||||
-The default value of this tunable is @samp{1}.
|
||||
+The default value of this tunable is @samp{2}.
|
||||
@end deftp
|
||||
|
||||
@node Elision Tunables
|
@ -0,0 +1,357 @@
|
||||
commit 3a0588ae48fb35384a6bd33f9b66403badfa1262
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Tue Feb 8 15:22:49 2022 -0300
|
||||
|
||||
elf: Fix DFS sorting algorithm for LD_TRACE_LOADED_OBJECTS with missing libraries (BZ #28868)
|
||||
|
||||
On _dl_map_object the underlying file is not opened in trace mode
|
||||
(in other cases where the underlying file can't be opened,
|
||||
_dl_map_object quits with an error). If there any missing libraries
|
||||
being processed, they will not be considered on final nlist size
|
||||
passed on _dl_sort_maps later in the function. And it is then used by
|
||||
_dl_sort_maps_dfs on the stack allocated working maps:
|
||||
|
||||
222 /* Array to hold RPO sorting results, before we copy back to maps[]. */
|
||||
223 struct link_map *rpo[nmaps];
|
||||
224
|
||||
225 /* The 'head' position during each DFS iteration. Note that we start at
|
||||
226 one past the last element due to first-decrement-then-store (see the
|
||||
227 bottom of above dfs_traversal() routine). */
|
||||
228 struct link_map **rpo_head = &rpo[nmaps];
|
||||
|
||||
However while transversing the 'l_initfini' on dfs_traversal it will
|
||||
still consider the l_faked maps and thus update rpo more times than the
|
||||
allocated working 'rpo', overflowing the stack object.
|
||||
|
||||
As suggested in bugzilla, one option would be to avoid sorting the maps
|
||||
for trace mode. However I think ignoring l_faked object does make
|
||||
sense (there is one less constraint to call the sorting function), it
|
||||
allows a slight less stack usage for trace, and it is slight simpler
|
||||
solution.
|
||||
|
||||
The tests does trigger the stack overflow, however I tried to make
|
||||
it more generic to check different scenarios or missing objects.
|
||||
|
||||
Checked on x86_64-linux-gnu.
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(differences in backported tests)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 22a8060f7d3bb1a1..634c3113227d64a6 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -584,6 +584,11 @@ modules-names = \
|
||||
libmarkermod5-3 \
|
||||
libmarkermod5-4 \
|
||||
libmarkermod5-5 \
|
||||
+ libtracemod1-1 \
|
||||
+ libtracemod2-1 \
|
||||
+ libtracemod3-1 \
|
||||
+ libtracemod4-1 \
|
||||
+ libtracemod5-1 \
|
||||
ltglobmod1 \
|
||||
ltglobmod2 \
|
||||
neededobj1 \
|
||||
@@ -983,6 +988,11 @@ tests-special += \
|
||||
$(objpfx)tst-initorder2-cmp.out \
|
||||
$(objpfx)tst-unused-dep-cmp.out \
|
||||
$(objpfx)tst-unused-dep.out \
|
||||
+ $(objpfx)tst-trace1.out \
|
||||
+ $(objpfx)tst-trace2.out \
|
||||
+ $(objpfx)tst-trace3.out \
|
||||
+ $(objpfx)tst-trace4.out \
|
||||
+ $(objpfx)tst-trace5.out \
|
||||
# tests-special
|
||||
endif
|
||||
|
||||
@@ -2619,6 +2629,51 @@ $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig
|
||||
|
||||
$(objpfx)tst-dlmopen-gethostbyname: $(libdl)
|
||||
$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
|
||||
+
|
||||
+LDFLAGS-libtracemod1-1.so += -Wl,-soname,libtracemod1.so
|
||||
+LDFLAGS-libtracemod2-1.so += -Wl,-soname,libtracemod2.so
|
||||
+LDFLAGS-libtracemod3-1.so += -Wl,-soname,libtracemod3.so
|
||||
+LDFLAGS-libtracemod4-1.so += -Wl,-soname,libtracemod4.so
|
||||
+LDFLAGS-libtracemod5-1.so += -Wl,-soname,libtracemod5.so
|
||||
+
|
||||
+$(objpfx)libtracemod1-1.so: $(objpfx)libtracemod2-1.so \
|
||||
+ $(objpfx)libtracemod3-1.so
|
||||
+$(objpfx)libtracemod2-1.so: $(objpfx)libtracemod4-1.so \
|
||||
+ $(objpfx)libtracemod5-1.so
|
||||
+
|
||||
+define libtracemod-x
|
||||
+$(objpfx)libtracemod$(1)/libtracemod$(1).so: $(objpfx)libtracemod$(1)-1.so
|
||||
+ $$(make-target-directory)
|
||||
+ cp $$< $$@
|
||||
+endef
|
||||
+libtracemod-suffixes = 1 2 3 4 5
|
||||
+$(foreach i,$(libtracemod-suffixes), $(eval $(call libtracemod-x,$(i))))
|
||||
+
|
||||
+define tst-trace-skeleton
|
||||
+$(objpfx)tst-trace$(1).out: $(objpfx)libtracemod1/libtracemod1.so \
|
||||
+ $(objpfx)libtracemod2/libtracemod2.so \
|
||||
+ $(objpfx)libtracemod3/libtracemod3.so \
|
||||
+ $(objpfx)libtracemod4/libtracemod4.so \
|
||||
+ $(objpfx)libtracemod5/libtracemod5.so \
|
||||
+ $(..)scripts/tst-ld-trace.py \
|
||||
+ tst-trace$(1).exp
|
||||
+ ${ $(PYTHON) $(..)scripts/tst-ld-trace.py \
|
||||
+ "$(test-wrapper-env) $(elf-objpfx)$(rtld-installed-name) \
|
||||
+ --library-path $(common-objpfx):$(strip $(2)) \
|
||||
+ $(objpfx)libtracemod1/libtracemod1.so" tst-trace$(1).exp \
|
||||
+ } > $$@; $$(evaluate-test)
|
||||
+endef
|
||||
+
|
||||
+$(eval $(call tst-trace-skeleton,1,))
|
||||
+$(eval $(call tst-trace-skeleton,2,\
|
||||
+ $(objpfx)libtracemod2))
|
||||
+$(eval $(call tst-trace-skeleton,3,\
|
||||
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3))
|
||||
+$(eval $(call tst-trace-skeleton,4,\
|
||||
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4))
|
||||
+$(eval $(call tst-trace-skeleton,5,\
|
||||
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4:$(objpfx)libtracemod5))
|
||||
+
|
||||
$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
$(objpfx)tst-audit-tlsdesc-mod2.so \
|
||||
$(shared-thread-library)
|
||||
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
|
||||
index 9365d54c8e03e5f4..9ff589c8562b2dd1 100644
|
||||
--- a/elf/dl-deps.c
|
||||
+++ b/elf/dl-deps.c
|
||||
@@ -489,6 +489,8 @@ _dl_map_object_deps (struct link_map *map,
|
||||
|
||||
for (nlist = 0, runp = known; runp; runp = runp->next)
|
||||
{
|
||||
+ /* _dl_sort_maps ignores l_faked object, so it is safe to not consider
|
||||
+ them for nlist. */
|
||||
if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
|
||||
/* This can happen when we trace the loading. */
|
||||
--map->l_searchlist.r_nlist;
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 398a08f28c4d9ff1..99354dc08a010dd3 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -140,7 +140,9 @@ static void
|
||||
dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
bool *do_reldeps)
|
||||
{
|
||||
- if (map->l_visited)
|
||||
+ /* _dl_map_object_deps ignores l_faked objects when calculating the
|
||||
+ number of maps before calling _dl_sort_maps, ignore them as well. */
|
||||
+ if (map->l_visited || map->l_faked)
|
||||
return;
|
||||
|
||||
map->l_visited = 1;
|
||||
diff --git a/elf/libtracemod1-1.c b/elf/libtracemod1-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod1-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod2-1.c b/elf/libtracemod2-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod2-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod3-1.c b/elf/libtracemod3-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod3-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod4-1.c b/elf/libtracemod4-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod4-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod5-1.c b/elf/libtracemod5-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod5-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/tst-trace1.exp b/elf/tst-trace1.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..4a6f5211a68fe2c8
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace1.exp
|
||||
@@ -0,0 +1,4 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 0
|
||||
+libtracemod3.so 0
|
||||
diff --git a/elf/tst-trace2.exp b/elf/tst-trace2.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..e13506e2eb9aeca2
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace2.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 0
|
||||
+libtracemod4.so 0
|
||||
+libtracemod5.so 0
|
||||
diff --git a/elf/tst-trace3.exp b/elf/tst-trace3.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..e574549d12a53d72
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace3.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 1
|
||||
+libtracemod4.so 0
|
||||
+libtracemod5.so 0
|
||||
diff --git a/elf/tst-trace4.exp b/elf/tst-trace4.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..31ca97b35bde0009
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace4.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 1
|
||||
+libtracemod4.so 1
|
||||
+libtracemod5.so 0
|
||||
diff --git a/elf/tst-trace5.exp b/elf/tst-trace5.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..5d7d95372656396f
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace5.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 1
|
||||
+libtracemod4.so 1
|
||||
+libtracemod5.so 1
|
||||
diff --git a/scripts/tst-ld-trace.py b/scripts/tst-ld-trace.py
|
||||
new file mode 100755
|
||||
index 0000000000000000..f5a402800377f44b
|
||||
--- /dev/null
|
||||
+++ b/scripts/tst-ld-trace.py
|
||||
@@ -0,0 +1,108 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Dump the output of LD_TRACE_LOADED_OBJECTS in architecture neutral format.
|
||||
+# Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
+# Copyright The GNU Toolchain Authors.
|
||||
+# This file is part of the GNU C Library.
|
||||
+#
|
||||
+# The GNU C Library is free software; you can redistribute it and/or
|
||||
+# modify it under the terms of the GNU Lesser General Public
|
||||
+# License as published by the Free Software Foundation; either
|
||||
+# version 2.1 of the License, or (at your option) any later version.
|
||||
+#
|
||||
+# The GNU C Library is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+# Lesser General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU Lesser General Public
|
||||
+# License along with the GNU C Library; if not, see
|
||||
+# <https://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import argparse
|
||||
+import os
|
||||
+import subprocess
|
||||
+import sys
|
||||
+
|
||||
+try:
|
||||
+ subprocess.run
|
||||
+except:
|
||||
+ class _CompletedProcess:
|
||||
+ def __init__(self, args, returncode, stdout=None, stderr=None):
|
||||
+ self.args = args
|
||||
+ self.returncode = returncode
|
||||
+ self.stdout = stdout
|
||||
+ self.stderr = stderr
|
||||
+
|
||||
+ def _run(*popenargs, input=None, timeout=None, check=False, **kwargs):
|
||||
+ assert(timeout is None)
|
||||
+ with subprocess.Popen(*popenargs, **kwargs) as process:
|
||||
+ try:
|
||||
+ stdout, stderr = process.communicate(input)
|
||||
+ except:
|
||||
+ process.kill()
|
||||
+ process.wait()
|
||||
+ raise
|
||||
+ returncode = process.poll()
|
||||
+ if check and returncode:
|
||||
+ raise subprocess.CalledProcessError(returncode, popenargs)
|
||||
+ return _CompletedProcess(popenargs, returncode, stdout, stderr)
|
||||
+
|
||||
+ subprocess.run = _run
|
||||
+
|
||||
+def is_vdso(lib):
|
||||
+ return lib.startswith('linux-gate') or lib.startswith('linux-vdso')
|
||||
+
|
||||
+
|
||||
+def parse_trace(cmd, fref):
|
||||
+ new_env = os.environ.copy()
|
||||
+ new_env['LD_TRACE_LOADED_OBJECTS'] = '1'
|
||||
+ trace_out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True,
|
||||
+ universal_newlines=True, env=new_env).stdout
|
||||
+ trace = []
|
||||
+ for line in trace_out.splitlines():
|
||||
+ line = line.strip()
|
||||
+ if is_vdso(line):
|
||||
+ continue
|
||||
+ fields = line.split('=>' if '=>' in line else ' ')
|
||||
+ lib = os.path.basename(fields[0].strip())
|
||||
+ if lib.startswith('ld'):
|
||||
+ lib = 'ld'
|
||||
+ elif lib.startswith('libc'):
|
||||
+ lib = 'libc'
|
||||
+ found = 1 if fields[1].strip() != 'not found' else 0
|
||||
+ trace += ['{} {}'.format(lib, found)]
|
||||
+ trace = sorted(trace)
|
||||
+
|
||||
+ reference = sorted(line.replace('\n','') for line in fref.readlines())
|
||||
+
|
||||
+ ret = 0 if trace == reference else 1
|
||||
+ if ret != 0:
|
||||
+ for i in reference:
|
||||
+ if i not in trace:
|
||||
+ print("Only in {}: {}".format(fref.name, i))
|
||||
+ for i in trace:
|
||||
+ if i not in reference:
|
||||
+ print("Only in trace: {}".format(i))
|
||||
+
|
||||
+ sys.exit(ret)
|
||||
+
|
||||
+
|
||||
+def get_parser():
|
||||
+ parser = argparse.ArgumentParser(description=__doc__)
|
||||
+ parser.add_argument('command',
|
||||
+ help='comand to run')
|
||||
+ parser.add_argument('reference',
|
||||
+ help='reference file to compare')
|
||||
+ return parser
|
||||
+
|
||||
+
|
||||
+def main(argv):
|
||||
+ parser = get_parser()
|
||||
+ opts = parser.parse_args(argv)
|
||||
+ with open(opts.reference, 'r') as fref:
|
||||
+ # Remove the initial 'env' command.
|
||||
+ parse_trace(opts.command.split()[1:], fref)
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main(sys.argv[1:])
|
@ -0,0 +1,36 @@
|
||||
commit a2211c76c3b994099fd58a06d6072d7495d699cd
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Mar 18 18:18:35 2022 +0100
|
||||
|
||||
scripts/dso-ordering-test.py: Fix C&P error in * callrefs processing
|
||||
|
||||
The elf/dso-sort-tests-src subdirectory is not changed by this commit,
|
||||
so it seems that the cut-and-paste error was not material.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index bde0406be9da14fc..ee476c810c76f1b0 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -551,17 +551,17 @@ def process_testcase(t):
|
||||
if obj in t.deps:
|
||||
deps = t.deps[obj]
|
||||
if '*' in deps:
|
||||
- t.deps[obj].remove('*')
|
||||
+ deps.remove('*')
|
||||
t.add_deps([obj], non_dep_tgt_objs)
|
||||
if obj in t.callrefs:
|
||||
deps = t.callrefs[obj]
|
||||
if '*' in deps:
|
||||
- t.deps[obj].remove('*')
|
||||
+ deps.remove('*')
|
||||
t.add_callrefs([obj], non_dep_tgt_objs)
|
||||
if "#" in t.deps:
|
||||
deps = t.deps["#"]
|
||||
if '*' in deps:
|
||||
- t.deps["#"].remove('*')
|
||||
+ deps.remove('*')
|
||||
t.add_deps(["#"], non_dep_tgt_objs)
|
||||
|
||||
# If no main program was specified in dependency description, make a
|
@ -0,0 +1,37 @@
|
||||
commit 183d99737298bb3200f0610fdcd1c7549c8ed560
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 6 07:38:10 2022 +0200
|
||||
|
||||
scripts/dso-ordering-test.py: Generate program run-time dependencies
|
||||
|
||||
The main program needs to depend on all shared objects, even objects
|
||||
that have link-time dependencies among shared objects. Filtering
|
||||
out shared objects that already have an link-time dependencies is not
|
||||
necessary here; make will do this automatically.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index ee476c810c76f1b0..43b5ec4d920ad6a3 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -707,13 +707,12 @@ def process_testcase(t):
|
||||
"\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
makefile.write (rule)
|
||||
|
||||
- not_depended_objs = find_objs_not_depended_on(test_descr)
|
||||
- if not_depended_objs:
|
||||
- depstr = ""
|
||||
- for dep in not_depended_objs:
|
||||
- depstr += (" $(objpfx)" + test_subdir + "/"
|
||||
- + test_name + "-" + dep + ".so")
|
||||
- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
|
||||
+ # Ensure that all shared objects are built before running the
|
||||
+ # test, whether there link-time dependencies or not.
|
||||
+ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
|
||||
+ for dep in test_descr.objs]
|
||||
+ makefile.write("$(objpfx){}.out: {}\n".format(
|
||||
+ base_test_name, " ".join(depobjs)))
|
||||
|
||||
# Add main executable to test-srcs
|
||||
makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))
|
@ -0,0 +1,49 @@
|
||||
Backport of this Fedora Rawhide commit but split out into a distinct
|
||||
patch.
|
||||
|
||||
commit 72195d44855ab96875f117acb75c37f98dcb26a9
|
||||
Author: Carlos O'Donell <carlos@redhat.com>
|
||||
Date: Thu Jun 6 23:58:21 2019 -0400
|
||||
|
||||
locale: Fix C.UTF-8 ranges.
|
||||
|
||||
The ellipsis range support only allows <Uxxxx> or <Uxxxxxxxx> as
|
||||
valid unicode code points, otherwise it treats it as a symbol and
|
||||
since we don't define the symbol the entire range is unused.
|
||||
|
||||
diff --git a/localedata/locales/C b/localedata/locales/C
|
||||
index b2c2d1dc417cde69..30d9563213b8cb0f 100644
|
||||
--- a/localedata/locales/C
|
||||
+++ b/localedata/locales/C
|
||||
@@ -43,21 +43,21 @@ order_start forward
|
||||
<U0000>
|
||||
..
|
||||
<UFFFF>
|
||||
-<U10000>
|
||||
+<U00010000>
|
||||
..
|
||||
-<U1FFFF>
|
||||
-<U20000>
|
||||
+<U0001FFFF>
|
||||
+<U00020000>
|
||||
..
|
||||
-<U2FFFF>
|
||||
-<UE0000>
|
||||
+<U0002FFFF>
|
||||
+<U000E0000>
|
||||
..
|
||||
-<UEFFFF>
|
||||
-<UF0000>
|
||||
+<U000EFFFF>
|
||||
+<U000F0000>
|
||||
..
|
||||
-<UFFFFF>
|
||||
-<U100000>
|
||||
+<U000FFFFF>
|
||||
+<U00100000>
|
||||
..
|
||||
-<U10FFFF>
|
||||
+<U0010FFFF>
|
||||
UNDEFINED
|
||||
order_end
|
||||
END LC_COLLATE
|
@ -0,0 +1,185 @@
|
||||
commit 96cd0558bcd69481ccc42e1b392f0c0b36fce2b0
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Wed Nov 28 19:59:45 2018 +0100
|
||||
|
||||
support: Add signal support to support_capture_subprocess_check
|
||||
|
||||
Signal zero does not terminate a process, so it is safe to use negative
|
||||
values for signal numbers.
|
||||
|
||||
Adjust libio/tst-vtables-common.c to use this new functionality,
|
||||
instead of determining the termination status for a signal indirectly.
|
||||
|
||||
diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c
|
||||
index 5e3101206919fa1b..85e246cd1131f8e8 100644
|
||||
--- a/libio/tst-vtables-common.c
|
||||
+++ b/libio/tst-vtables-common.c
|
||||
@@ -380,21 +380,6 @@ without_compatibility_fflush (void *closure)
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
-/* Exit status after abnormal termination. */
|
||||
-static int termination_status;
|
||||
-
|
||||
-static void
|
||||
-init_termination_status (void)
|
||||
-{
|
||||
- pid_t pid = xfork ();
|
||||
- if (pid == 0)
|
||||
- abort ();
|
||||
- xwaitpid (pid, &termination_status, 0);
|
||||
-
|
||||
- TEST_VERIFY (WIFSIGNALED (termination_status));
|
||||
- TEST_COMPARE (WTERMSIG (termination_status), SIGABRT);
|
||||
-}
|
||||
-
|
||||
static void
|
||||
check_for_termination (const char *name, void (*callback) (void *))
|
||||
{
|
||||
@@ -404,7 +389,7 @@ check_for_termination (const char *name, void (*callback) (void *))
|
||||
shared->calls = 0;
|
||||
struct support_capture_subprocess proc
|
||||
= support_capture_subprocess (callback, NULL);
|
||||
- support_capture_subprocess_check (&proc, name, termination_status,
|
||||
+ support_capture_subprocess_check (&proc, name, -SIGABRT,
|
||||
sc_allow_stderr);
|
||||
const char *message
|
||||
= "Fatal error: glibc detected an invalid stdio handle\n";
|
||||
@@ -491,7 +476,6 @@ run_tests (bool initially_disabled)
|
||||
|
||||
shared = support_shared_allocate (sizeof (*shared));
|
||||
shared->initially_disabled = initially_disabled;
|
||||
- init_termination_status ();
|
||||
|
||||
if (initially_disabled)
|
||||
{
|
||||
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
|
||||
index d5eac84d09ae325f..2d2384e73df0d2d0 100644
|
||||
--- a/support/capture_subprocess.h
|
||||
+++ b/support/capture_subprocess.h
|
||||
@@ -55,13 +55,16 @@ enum support_capture_allow
|
||||
sc_allow_stderr = 0x04,
|
||||
};
|
||||
|
||||
-/* Check that the subprocess exited with STATUS and that only the
|
||||
- allowed outputs happened. ALLOWED is a combination of
|
||||
- support_capture_allow flags. Report errors under the CONTEXT
|
||||
- message. */
|
||||
+/* Check that the subprocess exited and that only the allowed outputs
|
||||
+ happened. If STATUS_OR_SIGNAL is nonnegative, it is the expected
|
||||
+ (decoded) exit status of the process, as returned by WEXITSTATUS.
|
||||
+ If STATUS_OR_SIGNAL is negative, -STATUS_OR_SIGNAL is the expected
|
||||
+ termination signal, as returned by WTERMSIG. ALLOWED is a
|
||||
+ combination of support_capture_allow flags. Report errors under
|
||||
+ the CONTEXT message. */
|
||||
void support_capture_subprocess_check (struct support_capture_subprocess *,
|
||||
- const char *context, int status,
|
||||
- int allowed)
|
||||
+ const char *context,
|
||||
+ int status_or_signal, int allowed)
|
||||
__attribute__ ((nonnull (1, 2)));
|
||||
|
||||
#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */
|
||||
diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c
|
||||
index ff5ee89fb02599ae..8b4c352c96227b78 100644
|
||||
--- a/support/support_capture_subprocess_check.c
|
||||
+++ b/support/support_capture_subprocess_check.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <stdio.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
+#include <sys/wait.h>
|
||||
|
||||
static void
|
||||
print_context (const char *context, bool *failed)
|
||||
@@ -31,9 +32,22 @@ print_context (const char *context, bool *failed)
|
||||
printf ("error: subprocess failed: %s\n", context);
|
||||
}
|
||||
|
||||
+static void
|
||||
+print_actual_status (struct support_capture_subprocess *proc)
|
||||
+{
|
||||
+ if (WIFEXITED (proc->status))
|
||||
+ printf ("error: actual exit status: %d [0x%x]\n",
|
||||
+ WEXITSTATUS (proc->status), proc->status);
|
||||
+ else if (WIFSIGNALED (proc->status))
|
||||
+ printf ("error: actual termination signal: %d [0x%x]\n",
|
||||
+ WTERMSIG (proc->status), proc->status);
|
||||
+ else
|
||||
+ printf ("error: actual undecoded exit status: [0x%x]\n", proc->status);
|
||||
+}
|
||||
+
|
||||
void
|
||||
support_capture_subprocess_check (struct support_capture_subprocess *proc,
|
||||
- const char *context, int status,
|
||||
+ const char *context, int status_or_signal,
|
||||
int allowed)
|
||||
{
|
||||
TEST_VERIFY ((allowed & sc_allow_none)
|
||||
@@ -44,11 +58,28 @@ support_capture_subprocess_check (struct support_capture_subprocess *proc,
|
||||
|| (allowed & sc_allow_stderr))));
|
||||
|
||||
bool failed = false;
|
||||
- if (proc->status != status)
|
||||
+ if (status_or_signal >= 0)
|
||||
{
|
||||
- print_context (context, &failed);
|
||||
- printf ("error: expected exit status: %d\n", status);
|
||||
- printf ("error: actual exit status: %d\n", proc->status);
|
||||
+ /* Expect regular termination. */
|
||||
+ if (!(WIFEXITED (proc->status)
|
||||
+ && WEXITSTATUS (proc->status) == status_or_signal))
|
||||
+ {
|
||||
+ print_context (context, &failed);
|
||||
+ printf ("error: expected exit status: %d\n", status_or_signal);
|
||||
+ print_actual_status (proc);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* status_or_signal < 0. Expect termination by signal. */
|
||||
+ if (!(WIFSIGNALED (proc->status)
|
||||
+ && WTERMSIG (proc->status) == -status_or_signal))
|
||||
+ {
|
||||
+ print_context (context, &failed);
|
||||
+ printf ("error: expected termination signal: %d\n",
|
||||
+ -status_or_signal);
|
||||
+ print_actual_status (proc);
|
||||
+ }
|
||||
}
|
||||
if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
|
||||
{
|
||||
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
|
||||
index 63b6699622f97fcc..99570879eedd65b1 100644
|
||||
--- a/support/tst-support_capture_subprocess.c
|
||||
+++ b/support/tst-support_capture_subprocess.c
|
||||
@@ -285,15 +285,29 @@ do_multiple_tests (enum test_type type)
|
||||
|
||||
check_stream ("stdout", &result.out, test.out);
|
||||
check_stream ("stderr", &result.err, test.err);
|
||||
+
|
||||
+ /* Allowed output for support_capture_subprocess_check. */
|
||||
+ int check_allow = 0;
|
||||
+ if (lengths[length_idx_stdout] > 0)
|
||||
+ check_allow |= sc_allow_stdout;
|
||||
+ if (lengths[length_idx_stderr] > 0)
|
||||
+ check_allow |= sc_allow_stderr;
|
||||
+ if (check_allow == 0)
|
||||
+ check_allow = sc_allow_none;
|
||||
+
|
||||
if (test.signal != 0)
|
||||
{
|
||||
TEST_VERIFY (WIFSIGNALED (result.status));
|
||||
TEST_VERIFY (WTERMSIG (result.status) == test.signal);
|
||||
+ support_capture_subprocess_check (&result, "signal",
|
||||
+ -SIGTERM, check_allow);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_VERIFY (WIFEXITED (result.status));
|
||||
TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
|
||||
+ support_capture_subprocess_check (&result, "exit",
|
||||
+ test.status, check_allow);
|
||||
}
|
||||
support_capture_subprocess_free (&result);
|
||||
free (test.out);
|
@ -0,0 +1,42 @@
|
||||
commit e37c2cf299b61ce18f62852f6c5624c27829b610
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Oct 31 18:48:43 2019 +0100
|
||||
|
||||
Move _dl_open_check to its original place in dl_open_worker
|
||||
|
||||
This reverts the non-test change from commit d0093c5cefb7f7a4143f
|
||||
("Call _dl_open_check after relocation [BZ #24259]"), given that
|
||||
the underlying bug has been fixed properly in commit 61b74477fa7f63
|
||||
("Remove all loaded objects if dlopen fails, ignoring NODELETE
|
||||
[BZ #20839]").
|
||||
|
||||
Tested on x86-64-linux-gnu, with and without --enable-cet.
|
||||
|
||||
Change-Id: I995a6cfb89f25d2b0cf5e606428c2a93eb48fc33
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 25838b073ac1edaf..e13968d4d7c4c83f 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -619,6 +619,8 @@ dl_open_worker (void *a)
|
||||
_dl_debug_state ();
|
||||
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||
|
||||
+ _dl_open_check (new);
|
||||
+
|
||||
/* Print scope information. */
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
|
||||
_dl_show_scope (new, 0);
|
||||
@@ -699,12 +701,6 @@ dl_open_worker (void *a)
|
||||
_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
|
||||
}
|
||||
|
||||
- /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE
|
||||
- object when _dl_open_check throws an exception. Move it after
|
||||
- relocation to avoid leaving the NODELETE object mapped without
|
||||
- relocation. */
|
||||
- _dl_open_check (new);
|
||||
-
|
||||
/* This only performs the memory allocations. The actual update of
|
||||
the scopes happens below, after failure is impossible. */
|
||||
resize_scopes (new);
|
@ -0,0 +1,27 @@
|
||||
commit 61a7c9df71ee4e6f94b56c20f0d37c6e17d5f284
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Dec 2 14:53:16 2019 +0100
|
||||
|
||||
elf/tst-dlopenfail: Disable --no-as-needed for tst-dlopenfailmod1.so
|
||||
|
||||
Otherwise, the shared object dependency which triggers the load
|
||||
failure is dropped, invalidating the test.
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index bf7c41f38be42184..467e810e784bb96d 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -1543,8 +1543,11 @@ LDFLAGS-tst-finilazyfailmod.so = \
|
||||
$(objpfx)tst-dlopenfail: $(libdl)
|
||||
$(objpfx)tst-dlopenfail.out: \
|
||||
$(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so
|
||||
-# Order matters here. tst-dlopenfaillinkmod.so's soname ensures
|
||||
-# a run-time loader failure.
|
||||
+# Order matters here. tst-dlopenfaillinkmod.so's soname ensures a
|
||||
+# run-time loader failure. --as-needed breaks this test because
|
||||
+# nothing actually references tst-dlopenfailmod2.so (with its soname
|
||||
+# tst-dlopenfail-missingmod.so).
|
||||
+LDFLAGS-tst-dlopenfailmod1.so = -Wl,--no-as-needed
|
||||
$(objpfx)tst-dlopenfailmod1.so: \
|
||||
$(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
|
||||
LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,328 @@
|
||||
commit f8ed116aa574435c6e28260f21963233682d3b57
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Dec 13 10:18:46 2019 +0100
|
||||
|
||||
dlopen: Rework handling of pending NODELETE status
|
||||
|
||||
Commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23 ("Block signals during
|
||||
the initial part of dlopen") was deemed necessary because of
|
||||
read-modify-write operations like the one in add_dependency in
|
||||
elf/dl-lookup.c. In the old code, we check for any kind of NODELETE
|
||||
status and bail out:
|
||||
|
||||
/* Redo the NODELETE check, as when dl_load_lock wasn't held
|
||||
yet this could have changed. */
|
||||
if (map->l_nodelete != link_map_nodelete_inactive)
|
||||
goto out;
|
||||
|
||||
And then set pending status (during relocation):
|
||||
|
||||
if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
map->l_nodelete = link_map_nodelete_pending;
|
||||
else
|
||||
map->l_nodelete = link_map_nodelete_active;
|
||||
|
||||
If a signal arrives during relocation and the signal handler, through
|
||||
lazy binding, adds a global scope dependency on the same map, it will
|
||||
set map->l_nodelete to link_map_nodelete_active. This will be
|
||||
overwritten with link_map_nodelete_pending by the dlopen relocation
|
||||
code.
|
||||
|
||||
To avoid such problems in relation to the l_nodelete member, this
|
||||
commit introduces two flags for active NODELETE status (irrevocable)
|
||||
and pending NODELETE status (revocable until activate_nodelete is
|
||||
invoked). As a result, NODELETE processing in dlopen does not
|
||||
introduce further reasons why lazy binding from signal handlers
|
||||
is unsafe during dlopen, and a subsequent commit can remove signal
|
||||
blocking from dlopen.
|
||||
|
||||
This does not address pre-existing issues (unrelated to the NODELETE
|
||||
changes) which make lazy binding in a signal handler during dlopen
|
||||
unsafe, such as the use of malloc in both cases.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index 243a028c443173c1..fa7f3e8174576e46 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -197,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* Check whether this object is still used. */
|
||||
if (l->l_type == lt_loaded
|
||||
&& l->l_direct_opencount == 0
|
||||
- && l->l_nodelete != link_map_nodelete_active
|
||||
+ && !l->l_nodelete_active
|
||||
/* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
|
||||
acquire is sufficient and correct. */
|
||||
&& atomic_load_acquire (&l->l_tls_dtor_count) == 0
|
||||
@@ -279,8 +279,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
|
||||
if (!used[i])
|
||||
{
|
||||
- assert (imap->l_type == lt_loaded
|
||||
- && imap->l_nodelete != link_map_nodelete_active);
|
||||
+ assert (imap->l_type == lt_loaded && !imap->l_nodelete_active);
|
||||
|
||||
/* Call its termination function. Do not do it for
|
||||
half-cooked objects. Temporarily disable exception
|
||||
@@ -820,7 +819,7 @@ _dl_close (void *_map)
|
||||
before we took the lock. There is no way to detect this (see below)
|
||||
so we proceed assuming this isn't the case. First see whether we
|
||||
can remove the object at all. */
|
||||
- if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active))
|
||||
+ if (__glibc_unlikely (map->l_nodelete_active))
|
||||
{
|
||||
/* Nope. Do nothing. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
|
||||
index 35a3f96a6296294a..01724a54f8840f9f 100644
|
||||
--- a/elf/dl-lookup.c
|
||||
+++ b/elf/dl-lookup.c
|
||||
@@ -187,6 +187,28 @@ enter_unique_sym (struct unique_sym *table, size_t size,
|
||||
table[idx].map = map;
|
||||
}
|
||||
|
||||
+/* Mark MAP as NODELETE according to the lookup mode in FLAGS. During
|
||||
+ initial relocation, NODELETE state is pending only. */
|
||||
+static void
|
||||
+mark_nodelete (struct link_map *map, int flags)
|
||||
+{
|
||||
+ if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
+ map->l_nodelete_pending = true;
|
||||
+ else
|
||||
+ map->l_nodelete_active = true;
|
||||
+}
|
||||
+
|
||||
+/* Return true if MAP is marked as NODELETE according to the lookup
|
||||
+ mode in FLAGS> */
|
||||
+static bool
|
||||
+is_nodelete (struct link_map *map, int flags)
|
||||
+{
|
||||
+ /* Non-pending NODELETE always counts. Pending NODELETE only counts
|
||||
+ during initial relocation processing. */
|
||||
+ return map->l_nodelete_active
|
||||
+ || ((flags & DL_LOOKUP_FOR_RELOCATE) && map->l_nodelete_pending);
|
||||
+}
|
||||
+
|
||||
/* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
|
||||
in the unique symbol table, creating a new entry if necessary.
|
||||
Return the matching symbol in RESULT. */
|
||||
@@ -311,8 +333,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
|
||||
enter_unique_sym (entries, size,
|
||||
new_hash, strtab + sym->st_name, sym, map);
|
||||
|
||||
- if (map->l_type == lt_loaded
|
||||
- && map->l_nodelete == link_map_nodelete_inactive)
|
||||
+ if (map->l_type == lt_loaded && !is_nodelete (map, flags))
|
||||
{
|
||||
/* Make sure we don't unload this object by
|
||||
setting the appropriate flag. */
|
||||
@@ -320,10 +341,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
|
||||
_dl_debug_printf ("\
|
||||
marking %s [%lu] as NODELETE due to unique symbol\n",
|
||||
map->l_name, map->l_ns);
|
||||
- if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
- map->l_nodelete = link_map_nodelete_pending;
|
||||
- else
|
||||
- map->l_nodelete = link_map_nodelete_active;
|
||||
+ mark_nodelete (map, flags);
|
||||
}
|
||||
}
|
||||
++tab->n_elements;
|
||||
@@ -586,7 +604,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
|
||||
dependencies may pick an dependency which can be dlclose'd, but
|
||||
such IFUNC resolvers are undefined anyway. */
|
||||
assert (map->l_type == lt_loaded);
|
||||
- if (map->l_nodelete != link_map_nodelete_inactive)
|
||||
+ if (is_nodelete (map, flags))
|
||||
return 0;
|
||||
|
||||
struct link_map_reldeps *l_reldeps
|
||||
@@ -694,17 +712,16 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
|
||||
|
||||
/* Redo the NODELETE check, as when dl_load_lock wasn't held
|
||||
yet this could have changed. */
|
||||
- if (map->l_nodelete != link_map_nodelete_inactive)
|
||||
+ if (is_nodelete (map, flags))
|
||||
goto out;
|
||||
|
||||
/* If the object with the undefined reference cannot be removed ever
|
||||
just make sure the same is true for the object which contains the
|
||||
definition. */
|
||||
- if (undef_map->l_type != lt_loaded
|
||||
- || (undef_map->l_nodelete != link_map_nodelete_inactive))
|
||||
+ if (undef_map->l_type != lt_loaded || is_nodelete (map, flags))
|
||||
{
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
|
||||
- && map->l_nodelete == link_map_nodelete_inactive)
|
||||
+ && !is_nodelete (map, flags))
|
||||
{
|
||||
if (undef_map->l_name[0] == '\0')
|
||||
_dl_debug_printf ("\
|
||||
@@ -716,11 +733,7 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n",
|
||||
map->l_name, map->l_ns,
|
||||
undef_map->l_name, undef_map->l_ns);
|
||||
}
|
||||
-
|
||||
- if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
- map->l_nodelete = link_map_nodelete_pending;
|
||||
- else
|
||||
- map->l_nodelete = link_map_nodelete_active;
|
||||
+ mark_nodelete (map, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -746,17 +759,14 @@ marking %s [%lu] as NODELETE due to reference to %s [%lu]\n",
|
||||
cannot be unloaded. This is semantically the correct
|
||||
behavior. */
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
|
||||
- && map->l_nodelete == link_map_nodelete_inactive)
|
||||
+ && !is_nodelete (map, flags))
|
||||
_dl_debug_printf ("\
|
||||
marking %s [%lu] as NODELETE due to memory allocation failure\n",
|
||||
map->l_name, map->l_ns);
|
||||
- if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
- /* In case of non-lazy binding, we could actually
|
||||
- report the memory allocation error, but for now, we
|
||||
- use the conservative approximation as well. */
|
||||
- map->l_nodelete = link_map_nodelete_pending;
|
||||
- else
|
||||
- map->l_nodelete = link_map_nodelete_active;
|
||||
+ /* In case of non-lazy binding, we could actually report
|
||||
+ the memory allocation error, but for now, we use the
|
||||
+ conservative approximation as well. */
|
||||
+ mark_nodelete (map, flags);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index c7ed85b7ee99a296..a382bfae8aa3a2f8 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -440,13 +440,17 @@ activate_nodelete (struct link_map *new)
|
||||
NODELETE status for objects outside the local scope. */
|
||||
for (struct link_map *l = GL (dl_ns)[new->l_ns]._ns_loaded; l != NULL;
|
||||
l = l->l_next)
|
||||
- if (l->l_nodelete == link_map_nodelete_pending)
|
||||
+ if (l->l_nodelete_pending)
|
||||
{
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
|
||||
_dl_debug_printf ("activating NODELETE for %s [%lu]\n",
|
||||
l->l_name, l->l_ns);
|
||||
|
||||
- l->l_nodelete = link_map_nodelete_active;
|
||||
+ l->l_nodelete_active = true;
|
||||
+
|
||||
+ /* This is just a debugging aid, to indicate that
|
||||
+ activate_nodelete has run for this map. */
|
||||
+ l->l_nodelete_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,10 +553,10 @@ dl_open_worker (void *a)
|
||||
if (__glibc_unlikely (mode & RTLD_NODELETE))
|
||||
{
|
||||
if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)
|
||||
- && new->l_nodelete == link_map_nodelete_inactive)
|
||||
+ && !new->l_nodelete_active)
|
||||
_dl_debug_printf ("marking %s [%lu] as NODELETE\n",
|
||||
new->l_name, new->l_ns);
|
||||
- new->l_nodelete = link_map_nodelete_active;
|
||||
+ new->l_nodelete_active = true;
|
||||
}
|
||||
|
||||
/* Finalize the addition to the global scope. */
|
||||
@@ -568,7 +572,7 @@ dl_open_worker (void *a)
|
||||
/* Schedule NODELETE marking for the directly loaded object if
|
||||
requested. */
|
||||
if (__glibc_unlikely (mode & RTLD_NODELETE))
|
||||
- new->l_nodelete = link_map_nodelete_pending;
|
||||
+ new->l_nodelete_pending = true;
|
||||
|
||||
/* Load that object's dependencies. */
|
||||
_dl_map_object_deps (new, NULL, 0, 0,
|
||||
@@ -680,7 +684,7 @@ dl_open_worker (void *a)
|
||||
_dl_start_profile ();
|
||||
|
||||
/* Prevent unloading the object. */
|
||||
- GL(dl_profile_map)->l_nodelete = link_map_nodelete_active;
|
||||
+ GL(dl_profile_map)->l_nodelete_active = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -879,9 +883,9 @@ no more namespaces available for dlmopen()"));
|
||||
happens inside dl_open_worker. */
|
||||
__libc_signal_restore_set (&args.original_signal_mask);
|
||||
|
||||
- /* All link_map_nodelete_pending objects should have been
|
||||
- deleted at this point, which is why it is not necessary
|
||||
- to reset the flag here. */
|
||||
+ /* All l_nodelete_pending objects should have been deleted
|
||||
+ at this point, which is why it is not necessary to reset
|
||||
+ the flag here. */
|
||||
}
|
||||
else
|
||||
__libc_signal_restore_set (&args.original_signal_mask);
|
||||
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
|
||||
index ea286abaea0128d1..78ba7e76db9706cc 100644
|
||||
--- a/elf/get-dynamic-info.h
|
||||
+++ b/elf/get-dynamic-info.h
|
||||
@@ -164,7 +164,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
{
|
||||
l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
|
||||
if (l->l_flags_1 & DF_1_NODELETE)
|
||||
- l->l_nodelete = link_map_nodelete_pending;
|
||||
+ l->l_nodelete_pending = true;
|
||||
|
||||
/* Only DT_1_SUPPORTED_MASK bits are supported, and we would like
|
||||
to assert this, but we can't. Users have been setting
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index a277b77cad6b52b1..e90fa79a0b332087 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -79,22 +79,6 @@ struct r_search_path_struct
|
||||
int malloced;
|
||||
};
|
||||
|
||||
-/* Type used by the l_nodelete member. */
|
||||
-enum link_map_nodelete
|
||||
-{
|
||||
- /* This link map can be deallocated. */
|
||||
- link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object. */
|
||||
-
|
||||
- /* This link map cannot be deallocated. */
|
||||
- link_map_nodelete_active,
|
||||
-
|
||||
- /* This link map cannot be deallocated after dlopen has succeded.
|
||||
- dlopen turns this into link_map_nodelete_active. dlclose treats
|
||||
- this intermediate state as link_map_nodelete_active. */
|
||||
- link_map_nodelete_pending,
|
||||
-};
|
||||
-
|
||||
-
|
||||
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||
members form a chain of all the shared objects loaded at startup.
|
||||
|
||||
@@ -218,10 +202,17 @@ struct link_map
|
||||
freed, ie. not allocated with
|
||||
the dummy malloc in ld.so. */
|
||||
|
||||
- /* Actually of type enum link_map_nodelete. Separate byte due to
|
||||
- a read in add_dependency in elf/dl-lookup.c outside the loader
|
||||
- lock. Only valid for l_type == lt_loaded. */
|
||||
- unsigned char l_nodelete;
|
||||
+ /* NODELETE status of the map. Only valid for maps of type
|
||||
+ lt_loaded. Lazy binding sets l_nodelete_active directly,
|
||||
+ potentially from signal handlers. Initial loading of an
|
||||
+ DF_1_NODELETE object set l_nodelete_pending. Relocation may
|
||||
+ set l_nodelete_pending as well. l_nodelete_pending maps are
|
||||
+ promoted to l_nodelete_active status in the final stages of
|
||||
+ dlopen, prior to calling ELF constructors. dlclose only
|
||||
+ refuses to unload l_nodelete_active maps, the pending status is
|
||||
+ ignored. */
|
||||
+ bool l_nodelete_active;
|
||||
+ bool l_nodelete_pending;
|
||||
|
||||
#include <link_map.h>
|
||||
|
@ -0,0 +1,134 @@
|
||||
commit f7649d5780aa4682393b9daedd653e4d9c12784c
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Dec 13 10:23:10 2019 +0100
|
||||
|
||||
dlopen: Do not block signals
|
||||
|
||||
Blocking signals causes issues with certain anti-malware solutions
|
||||
which rely on an unblocked SIGSYS signal for system calls they
|
||||
intercept.
|
||||
|
||||
This reverts commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23
|
||||
("Block signals during the initial part of dlopen") and adds
|
||||
comments related to async signal safety to active_nodelete and
|
||||
its caller.
|
||||
|
||||
Note that this does not make lazy binding async-signal-safe with regards
|
||||
to dlopen. It merely avoids introducing new async-signal-safety hazards
|
||||
as part of the NODELETE changes.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index a382bfae8aa3a2f8..d834b89754d2b073 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <atomic.h>
|
||||
#include <libc-internal.h>
|
||||
#include <array_length.h>
|
||||
-#include <internal-signals.h>
|
||||
|
||||
#include <dl-dst.h>
|
||||
#include <dl-prop.h>
|
||||
@@ -53,10 +52,6 @@ struct dl_open_args
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
|
||||
- /* Original signal mask. Used for unblocking signal handlers before
|
||||
- running ELF constructors. */
|
||||
- sigset_t original_signal_mask;
|
||||
-
|
||||
/* Original value of _ns_global_scope_pending_adds. Set by
|
||||
dl_open_worker. Only valid if nsid is a real namespace
|
||||
(non-negative). */
|
||||
@@ -446,6 +441,9 @@ activate_nodelete (struct link_map *new)
|
||||
_dl_debug_printf ("activating NODELETE for %s [%lu]\n",
|
||||
l->l_name, l->l_ns);
|
||||
|
||||
+ /* The flag can already be true at this point, e.g. a signal
|
||||
+ handler may have triggered lazy binding and set NODELETE
|
||||
+ status immediately. */
|
||||
l->l_nodelete_active = true;
|
||||
|
||||
/* This is just a debugging aid, to indicate that
|
||||
@@ -520,16 +518,12 @@ dl_open_worker (void *a)
|
||||
if (new == NULL)
|
||||
{
|
||||
assert (mode & RTLD_NOLOAD);
|
||||
- __libc_signal_restore_set (&args->original_signal_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (mode & __RTLD_SPROF))
|
||||
- {
|
||||
- /* This happens only if we load a DSO for 'sprof'. */
|
||||
- __libc_signal_restore_set (&args->original_signal_mask);
|
||||
- return;
|
||||
- }
|
||||
+ /* This happens only if we load a DSO for 'sprof'. */
|
||||
+ return;
|
||||
|
||||
/* This object is directly loaded. */
|
||||
++new->l_direct_opencount;
|
||||
@@ -565,7 +559,6 @@ dl_open_worker (void *a)
|
||||
|
||||
assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
||||
|
||||
- __libc_signal_restore_set (&args->original_signal_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -709,6 +702,12 @@ dl_open_worker (void *a)
|
||||
All memory allocations for new objects must have happened
|
||||
before. */
|
||||
|
||||
+ /* Finalize the NODELETE status first. This comes before
|
||||
+ update_scopes, so that lazy binding will not see pending NODELETE
|
||||
+ state for newly loaded objects. There is a compiler barrier in
|
||||
+ update_scopes which ensures that the changes from
|
||||
+ activate_nodelete are visible before new objects show up in the
|
||||
+ local scope. */
|
||||
activate_nodelete (new);
|
||||
|
||||
/* Second stage after resize_scopes: Actually perform the scope
|
||||
@@ -742,10 +741,6 @@ dl_open_worker (void *a)
|
||||
if (mode & RTLD_GLOBAL)
|
||||
add_to_global_resize (new);
|
||||
|
||||
- /* Unblock signals. Data structures are now consistent, and
|
||||
- application code may run. */
|
||||
- __libc_signal_restore_set (&args->original_signal_mask);
|
||||
-
|
||||
/* Run the initializer functions of new objects. Temporarily
|
||||
disable the exception handler, so that lazy binding failures are
|
||||
fatal. */
|
||||
@@ -835,10 +830,6 @@ no more namespaces available for dlmopen()"));
|
||||
args.argv = argv;
|
||||
args.env = env;
|
||||
|
||||
- /* Recursive lazy binding during manipulation of the dynamic loader
|
||||
- structures may result in incorrect behavior. */
|
||||
- __libc_signal_block_all (&args.original_signal_mask);
|
||||
-
|
||||
struct dl_exception exception;
|
||||
int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
|
||||
|
||||
@@ -879,16 +870,10 @@ no more namespaces available for dlmopen()"));
|
||||
|
||||
_dl_close_worker (args.map, true);
|
||||
|
||||
- /* Restore the signal mask. In the success case, this
|
||||
- happens inside dl_open_worker. */
|
||||
- __libc_signal_restore_set (&args.original_signal_mask);
|
||||
-
|
||||
/* All l_nodelete_pending objects should have been deleted
|
||||
at this point, which is why it is not necessary to reset
|
||||
the flag here. */
|
||||
}
|
||||
- else
|
||||
- __libc_signal_restore_set (&args.original_signal_mask);
|
||||
|
||||
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
|
||||
|
@ -0,0 +1,27 @@
|
||||
commit 5177d85b0c050a2333a0c4165c938dd422013d05
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Thu Jan 16 06:45:36 2020 -0800
|
||||
|
||||
Clear GL(dl_initfirst) when freeing its link_map memory [BZ# 25396]
|
||||
|
||||
We should clear GL(dl_initfirst) when freeing its link_map memory.
|
||||
|
||||
Tested on Fedora 31/x86-64 with CET.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index fa7f3e8174576e46..a9ecdff62dba88fb 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -749,6 +749,10 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
if (imap->l_runpath_dirs.dirs != (void *) -1)
|
||||
free (imap->l_runpath_dirs.dirs);
|
||||
|
||||
+ /* Clear GL(dl_initfirst) when freeing its link_map memory. */
|
||||
+ if (imap == GL(dl_initfirst))
|
||||
+ GL(dl_initfirst) = NULL;
|
||||
+
|
||||
free (imap);
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
commit a332bd1518af518c984fad73eba6f46dc5b2b2d4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Jan 16 16:53:58 2020 +0100
|
||||
|
||||
elf: Add elf/tst-dlopenfail-2 [BZ #25396]
|
||||
|
||||
Without CET, a jump into a newly loaded object through an overwritten
|
||||
link map often does not crash, it just executes some random code.
|
||||
CET detects this in some cases because the function pointer does not
|
||||
point to the start of a function in the replacement shared object,
|
||||
so there is no ENDBR instruction.
|
||||
|
||||
The new test uses a small shared object and the existing dangling
|
||||
link map to trigger the bug.
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(Test backport differences.)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 16a3e8dcda19b4ba..f1a16fe8ca594c57 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -192,7 +192,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
|
||||
tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
|
||||
tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \
|
||||
- tst-dlopenfail
|
||||
+ tst-dlopenfail tst-dlopenfail-2
|
||||
# reldep9
|
||||
tests-internal += loadtest unload unload2 circleload1 \
|
||||
neededtest neededtest2 neededtest3 neededtest4 \
|
||||
@@ -301,7 +301,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-sonamemove-linkmod1 \
|
||||
tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
|
||||
tst-initlazyfailmod tst-finilazyfailmod \
|
||||
- tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2
|
||||
+ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
|
||||
+ tst-dlopenfailmod3
|
||||
|
||||
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
tests += tst-gnu2-tls1
|
||||
@@ -1569,6 +1570,10 @@ $(objpfx)tst-dlopenfailmod1.so: \
|
||||
$(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
|
||||
LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
|
||||
$(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
|
||||
+$(objpfx)tst-dlopenfail-2: $(libdl)
|
||||
+$(objpfx)tst-dlopenfail.out: \
|
||||
+ $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so \
|
||||
+ $(objpfx)tst-dlopenfailmod3.so
|
||||
|
||||
$(objpfx)tst-dlopen-nodelete-reloc: $(libdl)
|
||||
$(objpfx)tst-dlopen-nodelete-reloc.out: \
|
||||
diff --git a/elf/tst-dlopenfail-2.c b/elf/tst-dlopenfail-2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..35bbde64abbb6603
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopenfail-2.c
|
||||
@@ -0,0 +1,59 @@
|
||||
+/* Test unrelated dlopen after dlopen failure involving NODELETE.
|
||||
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <dlfcn.h>
|
||||
+#include <errno.h>
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* This test uses libpthread as the canonical NODELETE module. If
|
||||
+ libpthread is no longer NODELETE because it has been merged into
|
||||
+ libc, the test needs to be updated. */
|
||||
+ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL);
|
||||
+
|
||||
+ /* This is expected to fail because of the missing dependency. */
|
||||
+ puts ("info: attempting to load tst-dlopenfailmod1.so");
|
||||
+ TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL);
|
||||
+ const char *message = dlerror ();
|
||||
+ TEST_COMPARE_STRING (message,
|
||||
+ "tst-dlopenfail-missingmod.so:"
|
||||
+ " cannot open shared object file:"
|
||||
+ " No such file or directory");
|
||||
+
|
||||
+ /* Open a small shared object. With a dangling GL (dl_initfirst)
|
||||
+ pointer, this is likely to crash because there is no longer any
|
||||
+ mapped text segment there (bug 25396). */
|
||||
+
|
||||
+ puts ("info: attempting to load tst-dlopenfailmod3.so");
|
||||
+ xdlclose (xdlopen ("tst-dlopenfailmod3.so", RTLD_NOW));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Do not perturb the dangling link map. With M_PERTURB, the link map
|
||||
+ appears to have l_init_called set, so there are no constructor
|
||||
+ calls and no crashes. */
|
||||
+#define TEST_NO_MALLOPT
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopenfailmod3.c b/elf/tst-dlopenfailmod3.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..636e971264292110
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopenfailmod3.c
|
||||
@@ -0,0 +1,17 @@
|
||||
+/* Empty module for the tst-dlopenfail-2 test.
|
||||
+ Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
@ -0,0 +1,33 @@
|
||||
commit ca136bb0a36d0a7056c926bfe5126873566efe40
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Oct 31 13:28:26 2019 +0100
|
||||
|
||||
Clarify purpose of assert in _dl_lookup_symbol_x
|
||||
|
||||
Only one of the currently defined flags is incompatible with versioned
|
||||
symbol lookups, so it makes sense to check for that flag and not its
|
||||
complement.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Gabriel F. T. Gomes <gabrielftg@linux.ibm.com>
|
||||
Change-Id: I3384349cef90cfd91862ebc34a4053f0c0a99404
|
||||
|
||||
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
|
||||
index 1d046caf017b582b..efbdb8deb3c0a9d4 100644
|
||||
--- a/elf/dl-lookup.c
|
||||
+++ b/elf/dl-lookup.c
|
||||
@@ -792,11 +792,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
|
||||
|
||||
bump_num_relocations ();
|
||||
|
||||
- /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
|
||||
- is allowed if we look up a versioned symbol. */
|
||||
- assert (version == NULL
|
||||
- || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
|
||||
- == 0);
|
||||
+ /* DL_LOOKUP_RETURN_NEWEST does not make sense for versioned
|
||||
+ lookups. */
|
||||
+ assert (version == NULL || !(flags & DL_LOOKUP_RETURN_NEWEST));
|
||||
|
||||
size_t i = 0;
|
||||
if (__glibc_unlikely (skip_map != NULL))
|
@ -0,0 +1,54 @@
|
||||
commit 2a764c6ee848dfe92cb2921ed3b14085f15d9e79
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Oct 31 13:23:06 2019 +0100
|
||||
|
||||
Enhance _dl_catch_exception to allow disabling exception handling
|
||||
|
||||
In some cases, it is necessary to introduce noexcept regions
|
||||
where raised dynamic loader exceptions (e.g., from lazy binding)
|
||||
are fatal, despite being nested in a code region with an active
|
||||
exception handler. This change enhances _dl_catch_exception with
|
||||
to provide such a capability. The existing function is reused,
|
||||
so that it is not necessary to introduce yet another function with
|
||||
a similar purpose.
|
||||
|
||||
Change-Id: Iec1bf642ff95a349fdde8040e9baf851ac7b8904
|
||||
|
||||
diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
|
||||
index d5f418ab1848f0c4..9cb002ccfed2c7b4 100644
|
||||
--- a/elf/dl-error-skeleton.c
|
||||
+++ b/elf/dl-error-skeleton.c
|
||||
@@ -173,6 +173,18 @@ int
|
||||
_dl_catch_exception (struct dl_exception *exception,
|
||||
void (*operate) (void *), void *args)
|
||||
{
|
||||
+ /* If exception is NULL, temporarily disable exception handling.
|
||||
+ Exceptions during operate (args) are fatal. */
|
||||
+ if (exception == NULL)
|
||||
+ {
|
||||
+ struct catch *const old = catch_hook;
|
||||
+ catch_hook = NULL;
|
||||
+ operate (args);
|
||||
+ /* If we get here, the operation was successful. */
|
||||
+ catch_hook = old;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
/* We need not handle `receiver' since setting a `catch' is handled
|
||||
before it. */
|
||||
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 95dc87519b80e0ec..cc2484033fe0d902 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -852,7 +852,9 @@ libc_hidden_proto (_dl_catch_error)
|
||||
|
||||
/* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero.
|
||||
Otherwise, store a copy of the raised exception in *EXCEPTION,
|
||||
- which has to be freed by _dl_exception_free. */
|
||||
+ which has to be freed by _dl_exception_free. As a special case, if
|
||||
+ EXCEPTION is null, call OPERATE (ARGS) with exception handling
|
||||
+ disabled (so that exceptions are fatal). */
|
||||
int _dl_catch_exception (struct dl_exception *exception,
|
||||
void (*operate) (void *), void *args);
|
||||
libc_hidden_proto (_dl_catch_exception)
|
@ -0,0 +1,42 @@
|
||||
commit fcb04b9aed26a737159ef7be9c5a6ad0994437dc
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Oct 31 13:28:49 2019 +0100
|
||||
|
||||
Introduce DL_LOOKUP_FOR_RELOCATE flag for _dl_lookup_symbol_x
|
||||
|
||||
This will allow changes in dependency processing during non-lazy
|
||||
binding, for more precise processing of NODELETE objects: During
|
||||
initial relocation in dlopen, the fate of NODELETE objects is still
|
||||
unclear, so objects which are depended upon by NODELETE objects
|
||||
cannot immediately be marked as NODELETE.
|
||||
|
||||
Change-Id: Ic7b94a3f7c4719a00ca8e6018088567824da0658
|
||||
|
||||
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
|
||||
index 053916eeae50467c..afeace4d3e49180c 100644
|
||||
--- a/elf/dl-reloc.c
|
||||
+++ b/elf/dl-reloc.c
|
||||
@@ -248,7 +248,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
v = (version); \
|
||||
_lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref), \
|
||||
scope, v, _tc, \
|
||||
- DL_LOOKUP_ADD_DEPENDENCY, NULL); \
|
||||
+ DL_LOOKUP_ADD_DEPENDENCY \
|
||||
+ | DL_LOOKUP_FOR_RELOCATE, NULL); \
|
||||
l->l_lookup_cache.ret = (*ref); \
|
||||
l->l_lookup_cache.value = _lr; })) \
|
||||
: l)
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index cc2484033fe0d902..6c5298a80bff8e96 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -908,6 +908,9 @@ enum
|
||||
DL_LOOKUP_RETURN_NEWEST = 2,
|
||||
/* Set if dl_lookup* called with GSCOPE lock held. */
|
||||
DL_LOOKUP_GSCOPE_LOCK = 4,
|
||||
+ /* Set if dl_lookup is called for non-lazy relocation processing
|
||||
+ from _dl_relocate_object in elf/dl-reloc.c. */
|
||||
+ DL_LOOKUP_FOR_RELOCATE = 8,
|
||||
};
|
||||
|
||||
/* Lookup versioned symbol. */
|
@ -0,0 +1,343 @@
|
||||
commit 79e0cd7b3c997e211fad44a81fd839dc5b2546e8
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Wed Nov 27 16:20:47 2019 +0100
|
||||
|
||||
Lazy binding failures during dlopen/dlclose must be fatal [BZ #24304]
|
||||
|
||||
If a lazy binding failure happens during the execution of an ELF
|
||||
constructor or destructor, the dynamic loader catches the error
|
||||
and reports it using the dlerror mechanism. This is undesirable
|
||||
because there could be other constructors and destructors that
|
||||
need processing (which are skipped), and the process is in an
|
||||
inconsistent state at this point. Therefore, we have to issue
|
||||
a fatal dynamic loader error error and terminate the process.
|
||||
|
||||
Note that the _dl_catch_exception in _dl_open is just an inner catch,
|
||||
to roll back some state locally. If called from dlopen, there is
|
||||
still an outer catch, which is why calling _dl_init via call_dl_init
|
||||
and a no-exception is required and cannot be avoiding by moving the
|
||||
_dl_init call directly into _dl_open.
|
||||
|
||||
_dl_fini does not need changes because it does not install an error
|
||||
handler, so errors are already fatal there.
|
||||
|
||||
Change-Id: I6b1addfe2e30f50a1781595f046f44173db9491a
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(Usual conflicts due to test backport differences.)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 74a240b3a68ff5e2..b752f6366400d221 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -191,7 +191,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
|
||||
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
|
||||
tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
|
||||
- tst-sonamemove-link tst-sonamemove-dlopen
|
||||
+ tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail
|
||||
# reldep9
|
||||
tests-internal += loadtest unload unload2 circleload1 \
|
||||
neededtest neededtest2 neededtest3 neededtest4 \
|
||||
@@ -281,7 +281,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
|
||||
tst-absolute-zero-lib tst-big-note-lib \
|
||||
tst-sonamemove-linkmod1 \
|
||||
- tst-sonamemove-runmod1 tst-sonamemove-runmod2
|
||||
+ tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
|
||||
+ tst-initlazyfailmod tst-finilazyfailmod
|
||||
|
||||
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
tests += tst-gnu2-tls1
|
||||
@@ -1526,3 +1527,13 @@ tst-libc_dlvsym-static-ENV = \
|
||||
$(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so
|
||||
|
||||
$(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
|
||||
+
|
||||
+$(objpfx)tst-initfinilazyfail: $(libdl)
|
||||
+$(objpfx)tst-initfinilazyfail.out: \
|
||||
+ $(objpfx)tst-initlazyfailmod.so $(objpfx)tst-finilazyfailmod.so
|
||||
+# Override -z defs, so that we can reference an undefined symbol.
|
||||
+# Force lazy binding for the same reason.
|
||||
+LDFLAGS-tst-initlazyfailmod.so = \
|
||||
+ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
|
||||
+LDFLAGS-tst-finilazyfailmod.so = \
|
||||
+ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index ecd6729704ea3294..88aeea25839a34e0 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -106,6 +106,30 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
|
||||
return false;
|
||||
}
|
||||
|
||||
+/* Invoke dstructors for CLOSURE (a struct link_map *). Called with
|
||||
+ exception handling temporarily disabled, to make errors fatal. */
|
||||
+static void
|
||||
+call_destructors (void *closure)
|
||||
+{
|
||||
+ struct link_map *map = closure;
|
||||
+
|
||||
+ if (map->l_info[DT_FINI_ARRAY] != NULL)
|
||||
+ {
|
||||
+ ElfW(Addr) *array =
|
||||
+ (ElfW(Addr) *) (map->l_addr
|
||||
+ + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
+ unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
+ / sizeof (ElfW(Addr)));
|
||||
+
|
||||
+ while (sz-- > 0)
|
||||
+ ((fini_t) array[sz]) ();
|
||||
+ }
|
||||
+
|
||||
+ /* Next try the old-style destructor. */
|
||||
+ if (map->l_info[DT_FINI] != NULL)
|
||||
+ DL_CALL_DT_FINI (map, ((void *) map->l_addr
|
||||
+ + map->l_info[DT_FINI]->d_un.d_ptr));
|
||||
+}
|
||||
|
||||
void
|
||||
_dl_close_worker (struct link_map *map, bool force)
|
||||
@@ -267,7 +291,8 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
&& (imap->l_flags_1 & DF_1_NODELETE) == 0);
|
||||
|
||||
/* Call its termination function. Do not do it for
|
||||
- half-cooked objects. */
|
||||
+ half-cooked objects. Temporarily disable exception
|
||||
+ handling, so that errors are fatal. */
|
||||
if (imap->l_init_called)
|
||||
{
|
||||
/* When debugging print a message first. */
|
||||
@@ -276,22 +301,9 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||
imap->l_name, nsid);
|
||||
|
||||
- if (imap->l_info[DT_FINI_ARRAY] != NULL)
|
||||
- {
|
||||
- ElfW(Addr) *array =
|
||||
- (ElfW(Addr) *) (imap->l_addr
|
||||
- + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
- unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
- / sizeof (ElfW(Addr)));
|
||||
-
|
||||
- while (sz-- > 0)
|
||||
- ((fini_t) array[sz]) ();
|
||||
- }
|
||||
-
|
||||
- /* Next try the old-style destructor. */
|
||||
- if (imap->l_info[DT_FINI] != NULL)
|
||||
- DL_CALL_DT_FINI (imap, ((void *) imap->l_addr
|
||||
- + imap->l_info[DT_FINI]->d_un.d_ptr));
|
||||
+ if (imap->l_info[DT_FINI_ARRAY] != NULL
|
||||
+ || imap->l_info[DT_FINI] != NULL)
|
||||
+ _dl_catch_exception (NULL, call_destructors, imap);
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 518a6cad699ec6d0..c9c0254ee74c4f4b 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -177,6 +177,23 @@ _dl_find_dso_for_object (const ElfW(Addr) addr)
|
||||
}
|
||||
rtld_hidden_def (_dl_find_dso_for_object);
|
||||
|
||||
+/* struct dl_init_args and call_dl_init are used to call _dl_init with
|
||||
+ exception handling disabled. */
|
||||
+struct dl_init_args
|
||||
+{
|
||||
+ struct link_map *new;
|
||||
+ int argc;
|
||||
+ char **argv;
|
||||
+ char **env;
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+call_dl_init (void *closure)
|
||||
+{
|
||||
+ struct dl_init_args *args = closure;
|
||||
+ _dl_init (args->new, args->argc, args->argv, args->env);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
dl_open_worker (void *a)
|
||||
{
|
||||
@@ -506,8 +523,19 @@ TLS generation counter wrapped! Please report this."));
|
||||
DL_STATIC_INIT (new);
|
||||
#endif
|
||||
|
||||
- /* Run the initializer functions of new objects. */
|
||||
- _dl_init (new, args->argc, args->argv, args->env);
|
||||
+ /* Run the initializer functions of new objects. Temporarily
|
||||
+ disable the exception handler, so that lazy binding failures are
|
||||
+ fatal. */
|
||||
+ {
|
||||
+ struct dl_init_args init_args =
|
||||
+ {
|
||||
+ .new = new,
|
||||
+ .argc = args->argc,
|
||||
+ .argv = args->argv,
|
||||
+ .env = args->env
|
||||
+ };
|
||||
+ _dl_catch_exception (NULL, call_dl_init, &init_args);
|
||||
+ }
|
||||
|
||||
/* Now we can make the new map available in the global scope. */
|
||||
if (mode & RTLD_GLOBAL)
|
||||
diff --git a/elf/tst-finilazyfailmod.c b/elf/tst-finilazyfailmod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..2670bd1a9400d0ef
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-finilazyfailmod.c
|
||||
@@ -0,0 +1,27 @@
|
||||
+/* Helper module for tst-initfinilazyfail: lazy binding failure in destructor.
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* An undefined function. Calling it will cause a lazy binding
|
||||
+ failure. */
|
||||
+void undefined_function (void);
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ undefined_function ();
|
||||
+}
|
||||
diff --git a/elf/tst-initfinilazyfail.c b/elf/tst-initfinilazyfail.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..9b4a3d0c0ffbb7c6
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-initfinilazyfail.c
|
||||
@@ -0,0 +1,84 @@
|
||||
+/* Test that lazy binding failures in constructors and destructors are fatal.
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <dlfcn.h>
|
||||
+#include <string.h>
|
||||
+#include <support/capture_subprocess.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+static void
|
||||
+test_constructor (void *closure)
|
||||
+{
|
||||
+ void *handle = dlopen ("tst-initlazyfailmod.so", RTLD_LAZY);
|
||||
+ if (handle == NULL)
|
||||
+ FAIL_EXIT (2, "dlopen did not terminate the process: %s", dlerror ());
|
||||
+ else
|
||||
+ FAIL_EXIT (2, "dlopen did not terminate the process (%p)", handle);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_destructor (void *closure)
|
||||
+{
|
||||
+ void *handle = xdlopen ("tst-finilazyfailmod.so", RTLD_LAZY);
|
||||
+ int ret = dlclose (handle);
|
||||
+ const char *message = dlerror ();
|
||||
+ if (message != NULL)
|
||||
+ FAIL_EXIT (2, "dlclose did not terminate the process: %d, %s",
|
||||
+ ret, message);
|
||||
+ else
|
||||
+ FAIL_EXIT (2, "dlopen did not terminate the process: %d", ret);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ {
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprocess (test_constructor, NULL);
|
||||
+ support_capture_subprocess_check (&proc, "constructor", 127,
|
||||
+ sc_allow_stderr);
|
||||
+ printf ("info: constructor failure output: [[%s]]\n", proc.err.buffer);
|
||||
+ TEST_VERIFY (strstr (proc.err.buffer,
|
||||
+ "tst-initfinilazyfail: symbol lookup error: ")
|
||||
+ != NULL);
|
||||
+ TEST_VERIFY (strstr (proc.err.buffer,
|
||||
+ "tst-initlazyfailmod.so: undefined symbol:"
|
||||
+ " undefined_function\n") != NULL);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ struct support_capture_subprocess proc
|
||||
+ = support_capture_subprocess (test_destructor, NULL);
|
||||
+ support_capture_subprocess_check (&proc, "destructor", 127,
|
||||
+ sc_allow_stderr);
|
||||
+ printf ("info: destructor failure output: [[%s]]\n", proc.err.buffer);
|
||||
+ TEST_VERIFY (strstr (proc.err.buffer,
|
||||
+ "tst-initfinilazyfail: symbol lookup error: ")
|
||||
+ != NULL);
|
||||
+ TEST_VERIFY (strstr (proc.err.buffer,
|
||||
+ "tst-finilazyfailmod.so: undefined symbol:"
|
||||
+ " undefined_function\n") != NULL);
|
||||
+ support_capture_subprocess_free (&proc);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-initlazyfailmod.c b/elf/tst-initlazyfailmod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..36348b58d634d2bb
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-initlazyfailmod.c
|
||||
@@ -0,0 +1,27 @@
|
||||
+/* Helper module for tst-initfinilazyfail: lazy binding failure in constructor.
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* An undefined function. Calling it will cause a lazy binding
|
||||
+ failure. */
|
||||
+void undefined_function (void);
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ undefined_function ();
|
||||
+}
|
@ -0,0 +1,308 @@
|
||||
commit 440b7f8653e4ed8f6e1425145208050b795e9a6c
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Oct 31 18:25:39 2019 +0100
|
||||
|
||||
Avoid late failure in dlopen in global scope update [BZ #25112]
|
||||
|
||||
The call to add_to_global in dl_open_worker happens after running ELF
|
||||
constructors for new objects. At this point, proper recovery from
|
||||
malloc failure would be quite complicated: We would have to run the
|
||||
ELF destructors and close all opened objects, something that we
|
||||
currently do not do.
|
||||
|
||||
Instead, this change splits add_to_global into two phases,
|
||||
add_to_global_resize (which can raise an exception, called before ELF
|
||||
constructors run), and add_to_global_update (which cannot, called
|
||||
after ELF constructors). A complication arises due to recursive
|
||||
dlopen: After the inner dlopen consumes some space, the pre-allocation
|
||||
in the outer dlopen may no longer be sufficient. A new member in the
|
||||
namespace structure, _ns_global_scope_pending_adds keeps track of the
|
||||
maximum number of objects that need to be added to the global scope.
|
||||
This enables the inner add_to_global_resize call to take into account
|
||||
the needs of an outer dlopen.
|
||||
|
||||
Most code in the dynamic linker assumes that the number of global
|
||||
scope entries fits into an unsigned int (matching the r_nlist member
|
||||
of struct r_scop_elem). Therefore, change the type of
|
||||
_ns_global_scope_alloc to unsigned int (from size_t), and add overflow
|
||||
checks.
|
||||
|
||||
Change-Id: Ie08e2f318510d5a6a4bcb1c315f46791b5b77524
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index c9c0254ee74c4f4b..85db4f0ecb5f29ce 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -50,22 +50,38 @@ struct dl_open_args
|
||||
struct link_map *map;
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
+
|
||||
+ /* Original value of _ns_global_scope_pending_adds. Set by
|
||||
+ dl_open_worker. Only valid if nsid is a real namespace
|
||||
+ (non-negative). */
|
||||
+ unsigned int original_global_scope_pending_adds;
|
||||
+
|
||||
/* Original parameters to the program and the current environment. */
|
||||
int argc;
|
||||
char **argv;
|
||||
char **env;
|
||||
};
|
||||
|
||||
+/* Called in case the global scope cannot be extended. */
|
||||
+static void __attribute__ ((noreturn))
|
||||
+add_to_global_resize_failure (struct link_map *new)
|
||||
+{
|
||||
+ _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
|
||||
+ N_ ("cannot extend global scope"));
|
||||
+}
|
||||
|
||||
-static int
|
||||
-add_to_global (struct link_map *new)
|
||||
+/* Grow the global scope array for the namespace, so that all the new
|
||||
+ global objects can be added later in add_to_global_update, without
|
||||
+ risk of memory allocation failure. add_to_global_resize raises
|
||||
+ exceptions for memory allocation errors. */
|
||||
+static void
|
||||
+add_to_global_resize (struct link_map *new)
|
||||
{
|
||||
- struct link_map **new_global;
|
||||
- unsigned int to_add = 0;
|
||||
- unsigned int cnt;
|
||||
+ struct link_namespaces *ns = &GL (dl_ns)[new->l_ns];
|
||||
|
||||
/* Count the objects we have to put in the global scope. */
|
||||
- for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
|
||||
+ unsigned int to_add = 0;
|
||||
+ for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
|
||||
if (new->l_searchlist.r_list[cnt]->l_global == 0)
|
||||
++to_add;
|
||||
|
||||
@@ -83,47 +99,51 @@ add_to_global (struct link_map *new)
|
||||
in an realloc() call. Therefore we allocate a completely new
|
||||
array the first time we have to add something to the locale scope. */
|
||||
|
||||
- struct link_namespaces *ns = &GL(dl_ns)[new->l_ns];
|
||||
+ if (__builtin_add_overflow (ns->_ns_global_scope_pending_adds, to_add,
|
||||
+ &ns->_ns_global_scope_pending_adds))
|
||||
+ add_to_global_resize_failure (new);
|
||||
+
|
||||
+ unsigned int new_size = 0; /* 0 means no new allocation. */
|
||||
+ void *old_global = NULL; /* Old allocation if free-able. */
|
||||
+
|
||||
+ /* Minimum required element count for resizing. Adjusted below for
|
||||
+ an exponential resizing policy. */
|
||||
+ size_t required_new_size;
|
||||
+ if (__builtin_add_overflow (ns->_ns_main_searchlist->r_nlist,
|
||||
+ ns->_ns_global_scope_pending_adds,
|
||||
+ &required_new_size))
|
||||
+ add_to_global_resize_failure (new);
|
||||
+
|
||||
if (ns->_ns_global_scope_alloc == 0)
|
||||
{
|
||||
- /* This is the first dynamic object given global scope. */
|
||||
- ns->_ns_global_scope_alloc
|
||||
- = ns->_ns_main_searchlist->r_nlist + to_add + 8;
|
||||
- new_global = (struct link_map **)
|
||||
- malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *));
|
||||
- if (new_global == NULL)
|
||||
- {
|
||||
- ns->_ns_global_scope_alloc = 0;
|
||||
- nomem:
|
||||
- _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
|
||||
- N_("cannot extend global scope"));
|
||||
- return 1;
|
||||
- }
|
||||
+ if (__builtin_add_overflow (required_new_size, 8, &new_size))
|
||||
+ add_to_global_resize_failure (new);
|
||||
+ }
|
||||
+ else if (required_new_size > ns->_ns_global_scope_alloc)
|
||||
+ {
|
||||
+ if (__builtin_mul_overflow (required_new_size, 2, &new_size))
|
||||
+ add_to_global_resize_failure (new);
|
||||
|
||||
- /* Copy over the old entries. */
|
||||
- ns->_ns_main_searchlist->r_list
|
||||
- = memcpy (new_global, ns->_ns_main_searchlist->r_list,
|
||||
- (ns->_ns_main_searchlist->r_nlist
|
||||
- * sizeof (struct link_map *)));
|
||||
+ /* The old array was allocated with our malloc, not the minimal
|
||||
+ malloc. */
|
||||
+ old_global = ns->_ns_main_searchlist->r_list;
|
||||
}
|
||||
- else if (ns->_ns_main_searchlist->r_nlist + to_add
|
||||
- > ns->_ns_global_scope_alloc)
|
||||
+
|
||||
+ if (new_size > 0)
|
||||
{
|
||||
- /* We have to extend the existing array of link maps in the
|
||||
- main map. */
|
||||
- struct link_map **old_global
|
||||
- = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list;
|
||||
- size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2);
|
||||
-
|
||||
- new_global = (struct link_map **)
|
||||
- malloc (new_nalloc * sizeof (struct link_map *));
|
||||
+ size_t allocation_size;
|
||||
+ if (__builtin_mul_overflow (new_size, sizeof (struct link_map *),
|
||||
+ &allocation_size))
|
||||
+ add_to_global_resize_failure (new);
|
||||
+ struct link_map **new_global = malloc (allocation_size);
|
||||
if (new_global == NULL)
|
||||
- goto nomem;
|
||||
+ add_to_global_resize_failure (new);
|
||||
|
||||
- memcpy (new_global, old_global,
|
||||
- ns->_ns_global_scope_alloc * sizeof (struct link_map *));
|
||||
+ /* Copy over the old entries. */
|
||||
+ memcpy (new_global, ns->_ns_main_searchlist->r_list,
|
||||
+ ns->_ns_main_searchlist->r_nlist * sizeof (struct link_map *));
|
||||
|
||||
- ns->_ns_global_scope_alloc = new_nalloc;
|
||||
+ ns->_ns_global_scope_alloc = new_size;
|
||||
ns->_ns_main_searchlist->r_list = new_global;
|
||||
|
||||
if (!RTLD_SINGLE_THREAD_P)
|
||||
@@ -131,16 +151,28 @@ add_to_global (struct link_map *new)
|
||||
|
||||
free (old_global);
|
||||
}
|
||||
+}
|
||||
+
|
||||
+/* Actually add the new global objects to the global scope. Must be
|
||||
+ called after add_to_global_resize. This function cannot fail. */
|
||||
+static void
|
||||
+add_to_global_update (struct link_map *new)
|
||||
+{
|
||||
+ struct link_namespaces *ns = &GL (dl_ns)[new->l_ns];
|
||||
|
||||
/* Now add the new entries. */
|
||||
unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist;
|
||||
- for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
|
||||
+ for (unsigned int cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
|
||||
{
|
||||
struct link_map *map = new->l_searchlist.r_list[cnt];
|
||||
|
||||
if (map->l_global == 0)
|
||||
{
|
||||
map->l_global = 1;
|
||||
+
|
||||
+ /* The array has been resized by add_to_global_resize. */
|
||||
+ assert (new_nlist < ns->_ns_global_scope_alloc);
|
||||
+
|
||||
ns->_ns_main_searchlist->r_list[new_nlist++] = map;
|
||||
|
||||
/* We modify the global scope. Report this. */
|
||||
@@ -149,10 +181,15 @@ add_to_global (struct link_map *new)
|
||||
map->l_name, map->l_ns);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ /* Some of the pending adds have been performed by the loop above.
|
||||
+ Adjust the counter accordingly. */
|
||||
+ unsigned int added = new_nlist - ns->_ns_main_searchlist->r_nlist;
|
||||
+ assert (added <= ns->_ns_global_scope_pending_adds);
|
||||
+ ns->_ns_global_scope_pending_adds -= added;
|
||||
+
|
||||
atomic_write_barrier ();
|
||||
ns->_ns_main_searchlist->r_nlist = new_nlist;
|
||||
-
|
||||
- return 0;
|
||||
}
|
||||
|
||||
/* Search link maps in all namespaces for the DSO that contains the object at
|
||||
@@ -225,6 +262,10 @@ dl_open_worker (void *a)
|
||||
args->nsid = call_map->l_ns;
|
||||
}
|
||||
|
||||
+ /* Retain the old value, so that it can be restored. */
|
||||
+ args->original_global_scope_pending_adds
|
||||
+ = GL (dl_ns)[args->nsid]._ns_global_scope_pending_adds;
|
||||
+
|
||||
/* One might be tempted to assert that we are RT_CONSISTENT at this point, but that
|
||||
may not be true if this is a recursive call to dlopen. */
|
||||
_dl_debug_initialize (0, args->nsid);
|
||||
@@ -266,7 +307,10 @@ dl_open_worker (void *a)
|
||||
/* If the user requested the object to be in the global namespace
|
||||
but it is not so far, add it now. */
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
- (void) add_to_global (new);
|
||||
+ {
|
||||
+ add_to_global_resize (new);
|
||||
+ add_to_global_update (new);
|
||||
+ }
|
||||
|
||||
assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
||||
|
||||
@@ -523,6 +567,11 @@ TLS generation counter wrapped! Please report this."));
|
||||
DL_STATIC_INIT (new);
|
||||
#endif
|
||||
|
||||
+ /* Perform the necessary allocations for adding new global objects
|
||||
+ to the global scope below, via add_to_global_update. */
|
||||
+ if (mode & RTLD_GLOBAL)
|
||||
+ add_to_global_resize (new);
|
||||
+
|
||||
/* Run the initializer functions of new objects. Temporarily
|
||||
disable the exception handler, so that lazy binding failures are
|
||||
fatal. */
|
||||
@@ -539,10 +588,7 @@ TLS generation counter wrapped! Please report this."));
|
||||
|
||||
/* Now we can make the new map available in the global scope. */
|
||||
if (mode & RTLD_GLOBAL)
|
||||
- /* Move the object in the global namespace. */
|
||||
- if (add_to_global (new) != 0)
|
||||
- /* It failed. */
|
||||
- return;
|
||||
+ add_to_global_update (new);
|
||||
|
||||
#ifndef SHARED
|
||||
/* We must be the static _dl_open in libc.a. A static program that
|
||||
@@ -556,7 +602,6 @@ TLS generation counter wrapped! Please report this."));
|
||||
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||
}
|
||||
|
||||
-
|
||||
void *
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
|
||||
int argc, char *argv[], char *env[])
|
||||
@@ -624,6 +669,19 @@ no more namespaces available for dlmopen()"));
|
||||
_dl_unload_cache ();
|
||||
#endif
|
||||
|
||||
+ /* Do this for both the error and success cases. The old value has
|
||||
+ only been determined if the namespace ID was assigned (i.e., it
|
||||
+ is not __LM_ID_CALLER). In the success case, we actually may
|
||||
+ have consumed more pending adds than planned (because the local
|
||||
+ scopes overlap in case of a recursive dlopen, the inner dlopen
|
||||
+ doing some of the globalization work of the outer dlopen), so the
|
||||
+ old pending adds value is larger than absolutely necessary.
|
||||
+ Since it is just a conservative upper bound, this is harmless.
|
||||
+ The top-level dlopen call will restore the field to zero. */
|
||||
+ if (args.nsid >= 0)
|
||||
+ GL (dl_ns)[args.nsid]._ns_global_scope_pending_adds
|
||||
+ = args.original_global_scope_pending_adds;
|
||||
+
|
||||
/* See if an error occurred during loading. */
|
||||
if (__glibc_unlikely (exception.errstring != NULL))
|
||||
{
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 6c5298a80bff8e96..57fbefea3cb841e9 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -311,7 +311,14 @@ struct rtld_global
|
||||
/* This is zero at program start to signal that the global scope map is
|
||||
allocated by rtld. Later it keeps the size of the map. It might be
|
||||
reset if in _dl_close if the last global object is removed. */
|
||||
- size_t _ns_global_scope_alloc;
|
||||
+ unsigned int _ns_global_scope_alloc;
|
||||
+
|
||||
+ /* During dlopen, this is the number of objects that still need to
|
||||
+ be added to the global scope map. It has to be taken into
|
||||
+ account when resizing the map, for future map additions after
|
||||
+ recursive dlopen calls from ELF constructors. */
|
||||
+ unsigned int _ns_global_scope_pending_adds;
|
||||
+
|
||||
/* Search table for unique objects. */
|
||||
struct unique_sym_table
|
||||
{
|
@ -0,0 +1,490 @@
|
||||
commit a509eb117fac1d764b15eba64993f4bdb63d7f3c
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Wed Nov 27 16:37:17 2019 +0100
|
||||
|
||||
Avoid late dlopen failure due to scope, TLS slotinfo updates [BZ #25112]
|
||||
|
||||
This change splits the scope and TLS slotinfo updates in dlopen into
|
||||
two parts: one to resize the data structures, and one to actually apply
|
||||
the update. The call to add_to_global_resize in dl_open_worker is moved
|
||||
before the demarcation point at which no further memory allocations are
|
||||
allowed.
|
||||
|
||||
_dl_add_to_slotinfo is adjusted to make the list update optional. There
|
||||
is some optimization possibility here because we could grow the slotinfo
|
||||
list of arrays in a single call, one the largest TLS modid is known.
|
||||
|
||||
This commit does not fix the fatal meory allocation failure in
|
||||
_dl_update_slotinfo. Ideally, this error during dlopen should be
|
||||
recoverable.
|
||||
|
||||
The update order of scopes and TLS data structures is retained, although
|
||||
it appears to be more correct to fully initialize TLS first, and then
|
||||
expose symbols in the newly loaded objects via the scope update.
|
||||
|
||||
Tested on x86_64-linux-gnu.
|
||||
|
||||
Change-Id: I240c58387dabda3ca1bcab48b02115175fa83d6c
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 85db4f0ecb5f29ce..b330cff7d349224a 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <stap-probe.h>
|
||||
#include <atomic.h>
|
||||
#include <libc-internal.h>
|
||||
+#include <array_length.h>
|
||||
|
||||
#include <dl-dst.h>
|
||||
#include <dl-prop.h>
|
||||
@@ -214,6 +215,215 @@ _dl_find_dso_for_object (const ElfW(Addr) addr)
|
||||
}
|
||||
rtld_hidden_def (_dl_find_dso_for_object);
|
||||
|
||||
+/* Return true if NEW is found in the scope for MAP. */
|
||||
+static size_t
|
||||
+scope_has_map (struct link_map *map, struct link_map *new)
|
||||
+{
|
||||
+ size_t cnt;
|
||||
+ for (cnt = 0; map->l_scope[cnt] != NULL; ++cnt)
|
||||
+ if (map->l_scope[cnt] == &new->l_searchlist)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+/* Return the length of the scope for MAP. */
|
||||
+static size_t
|
||||
+scope_size (struct link_map *map)
|
||||
+{
|
||||
+ size_t cnt;
|
||||
+ for (cnt = 0; map->l_scope[cnt] != NULL; )
|
||||
+ ++cnt;
|
||||
+ return cnt;
|
||||
+}
|
||||
+
|
||||
+/* Resize the scopes of depended-upon objects, so that the new object
|
||||
+ can be added later without further allocation of memory. This
|
||||
+ function can raise an exceptions due to malloc failure. */
|
||||
+static void
|
||||
+resize_scopes (struct link_map *new)
|
||||
+{
|
||||
+ /* If the file is not loaded now as a dependency, add the search
|
||||
+ list of the newly loaded object to the scope. */
|
||||
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ {
|
||||
+ struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
+
|
||||
+ /* If the initializer has been called already, the object has
|
||||
+ not been loaded here and now. */
|
||||
+ if (imap->l_init_called && imap->l_type == lt_loaded)
|
||||
+ {
|
||||
+ if (scope_has_map (imap, new))
|
||||
+ /* Avoid duplicates. */
|
||||
+ continue;
|
||||
+
|
||||
+ size_t cnt = scope_size (imap);
|
||||
+ if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max))
|
||||
+ {
|
||||
+ /* The l_scope array is too small. Allocate a new one
|
||||
+ dynamically. */
|
||||
+ size_t new_size;
|
||||
+ struct r_scope_elem **newp;
|
||||
+
|
||||
+ if (imap->l_scope != imap->l_scope_mem
|
||||
+ && imap->l_scope_max < array_length (imap->l_scope_mem))
|
||||
+ {
|
||||
+ /* If the current l_scope memory is not pointing to
|
||||
+ the static memory in the structure, but the
|
||||
+ static memory in the structure is large enough to
|
||||
+ use for cnt + 1 scope entries, then switch to
|
||||
+ using the static memory. */
|
||||
+ new_size = array_length (imap->l_scope_mem);
|
||||
+ newp = imap->l_scope_mem;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ new_size = imap->l_scope_max * 2;
|
||||
+ newp = (struct r_scope_elem **)
|
||||
+ malloc (new_size * sizeof (struct r_scope_elem *));
|
||||
+ if (newp == NULL)
|
||||
+ _dl_signal_error (ENOMEM, "dlopen", NULL,
|
||||
+ N_("cannot create scope list"));
|
||||
+ }
|
||||
+
|
||||
+ /* Copy the array and the terminating NULL. */
|
||||
+ memcpy (newp, imap->l_scope,
|
||||
+ (cnt + 1) * sizeof (imap->l_scope[0]));
|
||||
+ struct r_scope_elem **old = imap->l_scope;
|
||||
+
|
||||
+ imap->l_scope = newp;
|
||||
+
|
||||
+ if (old != imap->l_scope_mem)
|
||||
+ _dl_scope_free (old);
|
||||
+
|
||||
+ imap->l_scope_max = new_size;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Second stage of resize_scopes: Add NEW to the scopes. Also print
|
||||
+ debugging information about scopes if requested.
|
||||
+
|
||||
+ This function cannot raise an exception because all required memory
|
||||
+ has been allocated by a previous call to resize_scopes. */
|
||||
+static void
|
||||
+update_scopes (struct link_map *new)
|
||||
+{
|
||||
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ {
|
||||
+ struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
+ int from_scope = 0;
|
||||
+
|
||||
+ if (imap->l_init_called && imap->l_type == lt_loaded)
|
||||
+ {
|
||||
+ if (scope_has_map (imap, new))
|
||||
+ /* Avoid duplicates. */
|
||||
+ continue;
|
||||
+
|
||||
+ size_t cnt = scope_size (imap);
|
||||
+ /* Assert that resize_scopes has sufficiently enlarged the
|
||||
+ array. */
|
||||
+ assert (cnt + 1 < imap->l_scope_max);
|
||||
+
|
||||
+ /* First terminate the extended list. Otherwise a thread
|
||||
+ might use the new last element and then use the garbage
|
||||
+ at offset IDX+1. */
|
||||
+ imap->l_scope[cnt + 1] = NULL;
|
||||
+ atomic_write_barrier ();
|
||||
+ imap->l_scope[cnt] = &new->l_searchlist;
|
||||
+
|
||||
+ from_scope = cnt;
|
||||
+ }
|
||||
+
|
||||
+ /* Print scope information. */
|
||||
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
|
||||
+ _dl_show_scope (imap, from_scope);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Call _dl_add_to_slotinfo with DO_ADD set to false, to allocate
|
||||
+ space in GL (dl_tls_dtv_slotinfo_list). This can raise an
|
||||
+ exception. The return value is true if any of the new objects use
|
||||
+ TLS. */
|
||||
+static bool
|
||||
+resize_tls_slotinfo (struct link_map *new)
|
||||
+{
|
||||
+ bool any_tls = false;
|
||||
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ {
|
||||
+ struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
+
|
||||
+ /* Only add TLS memory if this object is loaded now and
|
||||
+ therefore is not yet initialized. */
|
||||
+ if (! imap->l_init_called && imap->l_tls_blocksize > 0)
|
||||
+ {
|
||||
+ _dl_add_to_slotinfo (imap, false);
|
||||
+ any_tls = true;
|
||||
+ }
|
||||
+ }
|
||||
+ return any_tls;
|
||||
+}
|
||||
+
|
||||
+/* Second stage of TLS update, after resize_tls_slotinfo. This
|
||||
+ function does not raise any exception. It should only be called if
|
||||
+ resize_tls_slotinfo returned true. */
|
||||
+static void
|
||||
+update_tls_slotinfo (struct link_map *new)
|
||||
+{
|
||||
+ unsigned int first_static_tls = new->l_searchlist.r_nlist;
|
||||
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ {
|
||||
+ struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
+
|
||||
+ /* Only add TLS memory if this object is loaded now and
|
||||
+ therefore is not yet initialized. */
|
||||
+ if (! imap->l_init_called && imap->l_tls_blocksize > 0)
|
||||
+ {
|
||||
+ _dl_add_to_slotinfo (imap, true);
|
||||
+
|
||||
+ if (imap->l_need_tls_init
|
||||
+ && first_static_tls == new->l_searchlist.r_nlist)
|
||||
+ first_static_tls = i;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
+ _dl_fatal_printf (N_("\
|
||||
+TLS generation counter wrapped! Please report this."));
|
||||
+
|
||||
+ /* We need a second pass for static tls data, because
|
||||
+ _dl_update_slotinfo must not be run while calls to
|
||||
+ _dl_add_to_slotinfo are still pending. */
|
||||
+ for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ {
|
||||
+ struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
+
|
||||
+ if (imap->l_need_tls_init
|
||||
+ && ! imap->l_init_called
|
||||
+ && imap->l_tls_blocksize > 0)
|
||||
+ {
|
||||
+ /* For static TLS we have to allocate the memory here and
|
||||
+ now, but we can delay updating the DTV. */
|
||||
+ imap->l_need_tls_init = 0;
|
||||
+#ifdef SHARED
|
||||
+ /* Update the slot information data for at least the
|
||||
+ generation of the DSO we are allocating data for. */
|
||||
+
|
||||
+ /* FIXME: This can terminate the process on memory
|
||||
+ allocation failure. It is not possible to raise
|
||||
+ exceptions from this context; to fix this bug,
|
||||
+ _dl_update_slotinfo would have to be split into two
|
||||
+ operations, similar to resize_scopes and update_scopes
|
||||
+ above. This is related to bug 16134. */
|
||||
+ _dl_update_slotinfo (imap->l_tls_modid);
|
||||
+#endif
|
||||
+
|
||||
+ GL(dl_init_static_tls) (imap);
|
||||
+ assert (imap->l_need_tls_init == 0);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* struct dl_init_args and call_dl_init are used to call _dl_init with
|
||||
exception handling disabled. */
|
||||
struct dl_init_args
|
||||
@@ -431,133 +641,40 @@ dl_open_worker (void *a)
|
||||
relocation. */
|
||||
_dl_open_check (new);
|
||||
|
||||
- /* If the file is not loaded now as a dependency, add the search
|
||||
- list of the newly loaded object to the scope. */
|
||||
- bool any_tls = false;
|
||||
- unsigned int first_static_tls = new->l_searchlist.r_nlist;
|
||||
- for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
- {
|
||||
- struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
- int from_scope = 0;
|
||||
+ /* This only performs the memory allocations. The actual update of
|
||||
+ the scopes happens below, after failure is impossible. */
|
||||
+ resize_scopes (new);
|
||||
|
||||
- /* If the initializer has been called already, the object has
|
||||
- not been loaded here and now. */
|
||||
- if (imap->l_init_called && imap->l_type == lt_loaded)
|
||||
- {
|
||||
- struct r_scope_elem **runp = imap->l_scope;
|
||||
- size_t cnt = 0;
|
||||
-
|
||||
- while (*runp != NULL)
|
||||
- {
|
||||
- if (*runp == &new->l_searchlist)
|
||||
- break;
|
||||
- ++cnt;
|
||||
- ++runp;
|
||||
- }
|
||||
-
|
||||
- if (*runp != NULL)
|
||||
- /* Avoid duplicates. */
|
||||
- continue;
|
||||
-
|
||||
- if (__glibc_unlikely (cnt + 1 >= imap->l_scope_max))
|
||||
- {
|
||||
- /* The 'r_scope' array is too small. Allocate a new one
|
||||
- dynamically. */
|
||||
- size_t new_size;
|
||||
- struct r_scope_elem **newp;
|
||||
-
|
||||
-#define SCOPE_ELEMS(imap) \
|
||||
- (sizeof (imap->l_scope_mem) / sizeof (imap->l_scope_mem[0]))
|
||||
+ /* Increase the size of the GL (dl_tls_dtv_slotinfo_list) data
|
||||
+ structure. */
|
||||
+ bool any_tls = resize_tls_slotinfo (new);
|
||||
|
||||
- if (imap->l_scope != imap->l_scope_mem
|
||||
- && imap->l_scope_max < SCOPE_ELEMS (imap))
|
||||
- {
|
||||
- new_size = SCOPE_ELEMS (imap);
|
||||
- newp = imap->l_scope_mem;
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- new_size = imap->l_scope_max * 2;
|
||||
- newp = (struct r_scope_elem **)
|
||||
- malloc (new_size * sizeof (struct r_scope_elem *));
|
||||
- if (newp == NULL)
|
||||
- _dl_signal_error (ENOMEM, "dlopen", NULL,
|
||||
- N_("cannot create scope list"));
|
||||
- }
|
||||
-
|
||||
- memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0]));
|
||||
- struct r_scope_elem **old = imap->l_scope;
|
||||
-
|
||||
- imap->l_scope = newp;
|
||||
-
|
||||
- if (old != imap->l_scope_mem)
|
||||
- _dl_scope_free (old);
|
||||
-
|
||||
- imap->l_scope_max = new_size;
|
||||
- }
|
||||
-
|
||||
- /* First terminate the extended list. Otherwise a thread
|
||||
- might use the new last element and then use the garbage
|
||||
- at offset IDX+1. */
|
||||
- imap->l_scope[cnt + 1] = NULL;
|
||||
- atomic_write_barrier ();
|
||||
- imap->l_scope[cnt] = &new->l_searchlist;
|
||||
-
|
||||
- /* Print only new scope information. */
|
||||
- from_scope = cnt;
|
||||
- }
|
||||
- /* Only add TLS memory if this object is loaded now and
|
||||
- therefore is not yet initialized. */
|
||||
- else if (! imap->l_init_called
|
||||
- /* Only if the module defines thread local data. */
|
||||
- && __builtin_expect (imap->l_tls_blocksize > 0, 0))
|
||||
- {
|
||||
- /* Now that we know the object is loaded successfully add
|
||||
- modules containing TLS data to the slot info table. We
|
||||
- might have to increase its size. */
|
||||
- _dl_add_to_slotinfo (imap);
|
||||
-
|
||||
- if (imap->l_need_tls_init
|
||||
- && first_static_tls == new->l_searchlist.r_nlist)
|
||||
- first_static_tls = i;
|
||||
-
|
||||
- /* We have to bump the generation counter. */
|
||||
- any_tls = true;
|
||||
- }
|
||||
-
|
||||
- /* Print scope information. */
|
||||
- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
|
||||
- _dl_show_scope (imap, from_scope);
|
||||
- }
|
||||
-
|
||||
- /* Bump the generation number if necessary. */
|
||||
- if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
- _dl_fatal_printf (N_("\
|
||||
-TLS generation counter wrapped! Please report this."));
|
||||
-
|
||||
- /* We need a second pass for static tls data, because _dl_update_slotinfo
|
||||
- must not be run while calls to _dl_add_to_slotinfo are still pending. */
|
||||
- for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
|
||||
- {
|
||||
- struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
-
|
||||
- if (imap->l_need_tls_init
|
||||
- && ! imap->l_init_called
|
||||
- && imap->l_tls_blocksize > 0)
|
||||
- {
|
||||
- /* For static TLS we have to allocate the memory here and
|
||||
- now, but we can delay updating the DTV. */
|
||||
- imap->l_need_tls_init = 0;
|
||||
-#ifdef SHARED
|
||||
- /* Update the slot information data for at least the
|
||||
- generation of the DSO we are allocating data for. */
|
||||
- _dl_update_slotinfo (imap->l_tls_modid);
|
||||
-#endif
|
||||
+ /* Perform the necessary allocations for adding new global objects
|
||||
+ to the global scope below. */
|
||||
+ if (mode & RTLD_GLOBAL)
|
||||
+ add_to_global_resize (new);
|
||||
|
||||
- GL(dl_init_static_tls) (imap);
|
||||
- assert (imap->l_need_tls_init == 0);
|
||||
- }
|
||||
- }
|
||||
+ /* Demarcation point: After this, no recoverable errors are allowed.
|
||||
+ All memory allocations for new objects must have happened
|
||||
+ before. */
|
||||
+
|
||||
+ /* Second stage after resize_scopes: Actually perform the scope
|
||||
+ update. After this, dlsym and lazy binding can bind to new
|
||||
+ objects. */
|
||||
+ update_scopes (new);
|
||||
+
|
||||
+ /* FIXME: It is unclear whether the order here is correct.
|
||||
+ Shouldn't new objects be made available for binding (and thus
|
||||
+ execution) only after there TLS data has been set up fully?
|
||||
+ Fixing bug 16134 will likely make this distinction less
|
||||
+ important. */
|
||||
+
|
||||
+ /* Second stage after resize_tls_slotinfo: Update the slotinfo data
|
||||
+ structures. */
|
||||
+ if (any_tls)
|
||||
+ /* FIXME: This calls _dl_update_slotinfo, which aborts the process
|
||||
+ on memory allocation failure. See bug 16134. */
|
||||
+ update_tls_slotinfo (new);
|
||||
|
||||
/* Notify the debugger all new objects have been relocated. */
|
||||
if (relocation_in_progress)
|
||||
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
|
||||
index c87caf13d6a97ba4..a2def280b7096960 100644
|
||||
--- a/elf/dl-tls.c
|
||||
+++ b/elf/dl-tls.c
|
||||
@@ -883,7 +883,7 @@ _dl_tls_get_addr_soft (struct link_map *l)
|
||||
|
||||
|
||||
void
|
||||
-_dl_add_to_slotinfo (struct link_map *l)
|
||||
+_dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
{
|
||||
/* Now that we know the object is loaded successfully add
|
||||
modules containing TLS data to the dtv info table. We
|
||||
@@ -939,6 +939,9 @@ cannot create TLS data structures"));
|
||||
}
|
||||
|
||||
/* Add the information into the slotinfo data structure. */
|
||||
- listp->slotinfo[idx].map = l;
|
||||
- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
+ if (do_add)
|
||||
+ {
|
||||
+ listp->slotinfo[idx].map = l;
|
||||
+ listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
+ }
|
||||
}
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index 4ec26a79cbb0aa4f..0aa1a2a19f649e16 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -2167,7 +2167,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
|
||||
/* Add object to slot information data if necessasy. */
|
||||
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
|
||||
- _dl_add_to_slotinfo (l);
|
||||
+ _dl_add_to_slotinfo (l, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2215,7 +2215,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
|
||||
/* Add object to slot information data if necessasy. */
|
||||
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
|
||||
- _dl_add_to_slotinfo (l);
|
||||
+ _dl_add_to_slotinfo (l, true);
|
||||
}
|
||||
HP_TIMING_NOW (stop);
|
||||
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 57fbefea3cb841e9..c6b7e61badbfd513 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -1135,8 +1135,15 @@ extern void *_dl_open (const char *name, int mode, const void *caller,
|
||||
old scope, OLD can't be freed until no thread is using it. */
|
||||
extern int _dl_scope_free (void *) attribute_hidden;
|
||||
|
||||
-/* Add module to slot information data. */
|
||||
-extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden;
|
||||
+
|
||||
+/* Add module to slot information data. If DO_ADD is false, only the
|
||||
+ required memory is allocated. Must be called with GL
|
||||
+ (dl_load_lock) acquired. If the function has already been called
|
||||
+ for the link map L with !do_add, then this function will not raise
|
||||
+ an exception, otherwise it is possible that it encounters a memory
|
||||
+ allocation failure. */
|
||||
+extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add)
|
||||
+ attribute_hidden;
|
||||
|
||||
/* Update slot information data for at least the generation of the
|
||||
module with the given index. */
|
@ -0,0 +1,619 @@
|
||||
commit f63b73814f74032c0e5d0a83300e3d864ef905e5
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Wed Nov 13 15:44:56 2019 +0100
|
||||
|
||||
Remove all loaded objects if dlopen fails, ignoring NODELETE [BZ #20839]
|
||||
|
||||
This introduces a “pending NODELETE” state in the link map, which is
|
||||
flipped to the persistent NODELETE state late in dlopen, via
|
||||
activate_nodelete. During initial relocation, symbol binding
|
||||
records pending NODELETE state only. dlclose ignores pending NODELETE
|
||||
state. Taken together, this results that a partially completed dlopen
|
||||
is rolled back completely because new NODELETE mappings are unloaded.
|
||||
|
||||
Tested on x86_64-linux-gnu and i386-linux-gnu.
|
||||
|
||||
Change-Id: Ib2a3d86af6f92d75baca65431d74783ee0dbc292
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(Usual conflicts due to test backport differences.)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index b752f6366400d221..bf7c41f38be42184 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -191,7 +191,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
|
||||
tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \
|
||||
tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \
|
||||
- tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail
|
||||
+ tst-sonamemove-link tst-sonamemove-dlopen tst-initfinilazyfail \
|
||||
+ tst-dlopenfail
|
||||
# reldep9
|
||||
tests-internal += loadtest unload unload2 circleload1 \
|
||||
neededtest neededtest2 neededtest3 neededtest4 \
|
||||
@@ -282,7 +283,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-absolute-zero-lib tst-big-note-lib \
|
||||
tst-sonamemove-linkmod1 \
|
||||
tst-sonamemove-runmod1 tst-sonamemove-runmod2 \
|
||||
- tst-initlazyfailmod tst-finilazyfailmod
|
||||
+ tst-initlazyfailmod tst-finilazyfailmod \
|
||||
+ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2
|
||||
|
||||
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
tests += tst-gnu2-tls1
|
||||
@@ -1537,3 +1539,13 @@ LDFLAGS-tst-initlazyfailmod.so = \
|
||||
-Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
|
||||
LDFLAGS-tst-finilazyfailmod.so = \
|
||||
-Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
|
||||
+
|
||||
+$(objpfx)tst-dlopenfail: $(libdl)
|
||||
+$(objpfx)tst-dlopenfail.out: \
|
||||
+ $(objpfx)tst-dlopenfailmod1.so $(objpfx)tst-dlopenfailmod2.so
|
||||
+# Order matters here. tst-dlopenfaillinkmod.so's soname ensures
|
||||
+# a run-time loader failure.
|
||||
+$(objpfx)tst-dlopenfailmod1.so: \
|
||||
+ $(shared-thread-library) $(objpfx)tst-dlopenfaillinkmod.so
|
||||
+LDFLAGS-tst-dlopenfaillinkmod.so = -Wl,-soname,tst-dlopenfail-missingmod.so
|
||||
+$(objpfx)tst-dlopenfailmod2.so: $(shared-thread-library)
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index 88aeea25839a34e0..243a028c443173c1 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -168,14 +168,6 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
char done[nloaded];
|
||||
struct link_map *maps[nloaded];
|
||||
|
||||
- /* Clear DF_1_NODELETE to force object deletion. We don't need to touch
|
||||
- l_tls_dtor_count because forced object deletion only happens when an
|
||||
- error occurs during object load. Destructor registration for TLS
|
||||
- non-POD objects should not have happened till then for this
|
||||
- object. */
|
||||
- if (force)
|
||||
- map->l_flags_1 &= ~DF_1_NODELETE;
|
||||
-
|
||||
/* Run over the list and assign indexes to the link maps and enter
|
||||
them into the MAPS array. */
|
||||
int idx = 0;
|
||||
@@ -205,7 +197,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* Check whether this object is still used. */
|
||||
if (l->l_type == lt_loaded
|
||||
&& l->l_direct_opencount == 0
|
||||
- && (l->l_flags_1 & DF_1_NODELETE) == 0
|
||||
+ && l->l_nodelete != link_map_nodelete_active
|
||||
/* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
|
||||
acquire is sufficient and correct. */
|
||||
&& atomic_load_acquire (&l->l_tls_dtor_count) == 0
|
||||
@@ -288,7 +280,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
if (!used[i])
|
||||
{
|
||||
assert (imap->l_type == lt_loaded
|
||||
- && (imap->l_flags_1 & DF_1_NODELETE) == 0);
|
||||
+ && imap->l_nodelete != link_map_nodelete_active);
|
||||
|
||||
/* Call its termination function. Do not do it for
|
||||
half-cooked objects. Temporarily disable exception
|
||||
@@ -828,7 +820,7 @@ _dl_close (void *_map)
|
||||
before we took the lock. There is no way to detect this (see below)
|
||||
so we proceed assuming this isn't the case. First see whether we
|
||||
can remove the object at all. */
|
||||
- if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE))
|
||||
+ if (__glibc_unlikely (map->l_nodelete == link_map_nodelete_active))
|
||||
{
|
||||
/* Nope. Do nothing. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
|
||||
index efbdb8deb3c0a9d4..c5e5857fb1fe2808 100644
|
||||
--- a/elf/dl-lookup.c
|
||||
+++ b/elf/dl-lookup.c
|
||||
@@ -192,9 +192,10 @@ enter_unique_sym (struct unique_sym *table, size_t size,
|
||||
Return the matching symbol in RESULT. */
|
||||
static void
|
||||
do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
|
||||
- const struct link_map *map, struct sym_val *result,
|
||||
+ struct link_map *map, struct sym_val *result,
|
||||
int type_class, const ElfW(Sym) *sym, const char *strtab,
|
||||
- const ElfW(Sym) *ref, const struct link_map *undef_map)
|
||||
+ const ElfW(Sym) *ref, const struct link_map *undef_map,
|
||||
+ int flags)
|
||||
{
|
||||
/* We have to determine whether we already found a symbol with this
|
||||
name before. If not then we have to add it to the search table.
|
||||
@@ -222,7 +223,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
|
||||
copy from the copy addressed through the
|
||||
relocation. */
|
||||
result->s = sym;
|
||||
- result->m = (struct link_map *) map;
|
||||
+ result->m = map;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -311,9 +312,19 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
|
||||
new_hash, strtab + sym->st_name, sym, map);
|
||||
|
||||
if (map->l_type == lt_loaded)
|
||||
- /* Make sure we don't unload this object by
|
||||
- setting the appropriate flag. */
|
||||
- ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
|
||||
+ {
|
||||
+ /* Make sure we don't unload this object by
|
||||
+ setting the appropriate flag. */
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
|
||||
+ && map->l_nodelete == link_map_nodelete_inactive)
|
||||
+ _dl_debug_printf ("\
|
||||
+marking %s [%lu] as NODELETE due to unique symbol\n",
|
||||
+ map->l_name, map->l_ns);
|
||||
+ if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
+ map->l_nodelete = link_map_nodelete_pending;
|
||||
+ else
|
||||
+ map->l_nodelete = link_map_nodelete_active;
|
||||
+ }
|
||||
}
|
||||
++tab->n_elements;
|
||||
|
||||
@@ -525,8 +536,9 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
|
||||
return 1;
|
||||
|
||||
case STB_GNU_UNIQUE:;
|
||||
- do_lookup_unique (undef_name, new_hash, map, result, type_class,
|
||||
- sym, strtab, ref, undef_map);
|
||||
+ do_lookup_unique (undef_name, new_hash, (struct link_map *) map,
|
||||
+ result, type_class, sym, strtab, ref,
|
||||
+ undef_map, flags);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
@@ -568,9 +580,13 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
|
||||
if (undef_map == map)
|
||||
return 0;
|
||||
|
||||
- /* Avoid references to objects which cannot be unloaded anyway. */
|
||||
+ /* Avoid references to objects which cannot be unloaded anyway. We
|
||||
+ do not need to record dependencies if this object goes away
|
||||
+ during dlopen failure, either. IFUNC resolvers with relocation
|
||||
+ dependencies may pick an dependency which can be dlclose'd, but
|
||||
+ such IFUNC resolvers are undefined anyway. */
|
||||
assert (map->l_type == lt_loaded);
|
||||
- if ((map->l_flags_1 & DF_1_NODELETE) != 0)
|
||||
+ if (map->l_nodelete != link_map_nodelete_inactive)
|
||||
return 0;
|
||||
|
||||
struct link_map_reldeps *l_reldeps
|
||||
@@ -678,16 +694,33 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
|
||||
|
||||
/* Redo the NODELETE check, as when dl_load_lock wasn't held
|
||||
yet this could have changed. */
|
||||
- if ((map->l_flags_1 & DF_1_NODELETE) != 0)
|
||||
+ if (map->l_nodelete != link_map_nodelete_inactive)
|
||||
goto out;
|
||||
|
||||
/* If the object with the undefined reference cannot be removed ever
|
||||
just make sure the same is true for the object which contains the
|
||||
definition. */
|
||||
if (undef_map->l_type != lt_loaded
|
||||
- || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
|
||||
+ || (undef_map->l_nodelete != link_map_nodelete_inactive))
|
||||
{
|
||||
- map->l_flags_1 |= DF_1_NODELETE;
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
|
||||
+ && map->l_nodelete == link_map_nodelete_inactive)
|
||||
+ {
|
||||
+ if (undef_map->l_name[0] == '\0')
|
||||
+ _dl_debug_printf ("\
|
||||
+marking %s [%lu] as NODELETE due to reference to main program\n",
|
||||
+ map->l_name, map->l_ns);
|
||||
+ else
|
||||
+ _dl_debug_printf ("\
|
||||
+marking %s [%lu] as NODELETE due to reference to %s [%lu]\n",
|
||||
+ map->l_name, map->l_ns,
|
||||
+ undef_map->l_name, undef_map->l_ns);
|
||||
+ }
|
||||
+
|
||||
+ if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
+ map->l_nodelete = link_map_nodelete_pending;
|
||||
+ else
|
||||
+ map->l_nodelete = link_map_nodelete_active;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -712,7 +745,18 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
|
||||
no fatal problem. We simply make sure the referenced object
|
||||
cannot be unloaded. This is semantically the correct
|
||||
behavior. */
|
||||
- map->l_flags_1 |= DF_1_NODELETE;
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
|
||||
+ && map->l_nodelete == link_map_nodelete_inactive)
|
||||
+ _dl_debug_printf ("\
|
||||
+marking %s [%lu] as NODELETE due to memory allocation failure\n",
|
||||
+ map->l_name, map->l_ns);
|
||||
+ if (flags & DL_LOOKUP_FOR_RELOCATE)
|
||||
+ /* In case of non-lazy binding, we could actually
|
||||
+ report the memory allocation error, but for now, we
|
||||
+ use the conservative approximation as well. */
|
||||
+ map->l_nodelete = link_map_nodelete_pending;
|
||||
+ else
|
||||
+ map->l_nodelete = link_map_nodelete_active;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index b330cff7d349224a..79c6e4c8ed1c9dfa 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -424,6 +424,40 @@ TLS generation counter wrapped! Please report this."));
|
||||
}
|
||||
}
|
||||
|
||||
+/* Mark the objects as NODELETE if required. This is delayed until
|
||||
+ after dlopen failure is not possible, so that _dl_close can clean
|
||||
+ up objects if necessary. */
|
||||
+static void
|
||||
+activate_nodelete (struct link_map *new, int mode)
|
||||
+{
|
||||
+ if (mode & RTLD_NODELETE || new->l_nodelete == link_map_nodelete_pending)
|
||||
+ {
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
|
||||
+ _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
|
||||
+ new->l_name, new->l_ns);
|
||||
+ new->l_nodelete = link_map_nodelete_active;
|
||||
+ }
|
||||
+
|
||||
+ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
+ {
|
||||
+ struct link_map *imap = new->l_searchlist.r_list[i];
|
||||
+ if (imap->l_nodelete == link_map_nodelete_pending)
|
||||
+ {
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES))
|
||||
+ _dl_debug_printf ("activating NODELETE for %s [%lu]\n",
|
||||
+ imap->l_name, imap->l_ns);
|
||||
+
|
||||
+ /* Only new objects should have set
|
||||
+ link_map_nodelete_pending. Existing objects should not
|
||||
+ have gained any new dependencies and therefore cannot
|
||||
+ reach NODELETE status. */
|
||||
+ assert (!imap->l_init_called || imap->l_type != lt_loaded);
|
||||
+
|
||||
+ imap->l_nodelete = link_map_nodelete_active;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* struct dl_init_args and call_dl_init are used to call _dl_init with
|
||||
exception handling disabled. */
|
||||
struct dl_init_args
|
||||
@@ -493,12 +527,6 @@ dl_open_worker (void *a)
|
||||
return;
|
||||
}
|
||||
|
||||
- /* Mark the object as not deletable if the RTLD_NODELETE flags was passed.
|
||||
- Do this early so that we don't skip marking the object if it was
|
||||
- already loaded. */
|
||||
- if (__glibc_unlikely (mode & RTLD_NODELETE))
|
||||
- new->l_flags_1 |= DF_1_NODELETE;
|
||||
-
|
||||
if (__glibc_unlikely (mode & __RTLD_SPROF))
|
||||
/* This happens only if we load a DSO for 'sprof'. */
|
||||
return;
|
||||
@@ -514,19 +542,37 @@ dl_open_worker (void *a)
|
||||
_dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||
|
||||
- /* If the user requested the object to be in the global namespace
|
||||
- but it is not so far, add it now. */
|
||||
+ /* If the user requested the object to be in the global
|
||||
+ namespace but it is not so far, prepare to add it now. This
|
||||
+ can raise an exception to do a malloc failure. */
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
+ add_to_global_resize (new);
|
||||
+
|
||||
+ /* Mark the object as not deletable if the RTLD_NODELETE flags
|
||||
+ was passed. */
|
||||
+ if (__glibc_unlikely (mode & RTLD_NODELETE))
|
||||
{
|
||||
- add_to_global_resize (new);
|
||||
- add_to_global_update (new);
|
||||
+ if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_FILES)
|
||||
+ && new->l_nodelete == link_map_nodelete_inactive)
|
||||
+ _dl_debug_printf ("marking %s [%lu] as NODELETE\n",
|
||||
+ new->l_name, new->l_ns);
|
||||
+ new->l_nodelete = link_map_nodelete_active;
|
||||
}
|
||||
|
||||
+ /* Finalize the addition to the global scope. */
|
||||
+ if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
+ add_to_global_update (new);
|
||||
+
|
||||
assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+ /* Schedule NODELETE marking for the directly loaded object if
|
||||
+ requested. */
|
||||
+ if (__glibc_unlikely (mode & RTLD_NODELETE))
|
||||
+ new->l_nodelete = link_map_nodelete_pending;
|
||||
+
|
||||
/* Load that object's dependencies. */
|
||||
_dl_map_object_deps (new, NULL, 0, 0,
|
||||
mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
|
||||
@@ -598,6 +644,14 @@ dl_open_worker (void *a)
|
||||
|
||||
int relocation_in_progress = 0;
|
||||
|
||||
+ /* Perform relocation. This can trigger lazy binding in IFUNC
|
||||
+ resolvers. For NODELETE mappings, these dependencies are not
|
||||
+ recorded because the flag has not been applied to the newly
|
||||
+ loaded objects. This means that upon dlopen failure, these
|
||||
+ NODELETE objects can be unloaded despite existing references to
|
||||
+ them. However, such relocation dependencies in IFUNC resolvers
|
||||
+ are undefined anyway, so this is not a problem. */
|
||||
+
|
||||
for (unsigned int i = nmaps; i-- > 0; )
|
||||
{
|
||||
l = maps[i];
|
||||
@@ -627,7 +681,7 @@ dl_open_worker (void *a)
|
||||
_dl_start_profile ();
|
||||
|
||||
/* Prevent unloading the object. */
|
||||
- GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
|
||||
+ GL(dl_profile_map)->l_nodelete = link_map_nodelete_active;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -658,6 +712,8 @@ dl_open_worker (void *a)
|
||||
All memory allocations for new objects must have happened
|
||||
before. */
|
||||
|
||||
+ activate_nodelete (new, mode);
|
||||
+
|
||||
/* Second stage after resize_scopes: Actually perform the scope
|
||||
update. After this, dlsym and lazy binding can bind to new
|
||||
objects. */
|
||||
@@ -817,6 +873,10 @@ no more namespaces available for dlmopen()"));
|
||||
GL(dl_tls_dtv_gaps) = true;
|
||||
|
||||
_dl_close_worker (args.map, true);
|
||||
+
|
||||
+ /* All link_map_nodelete_pending objects should have been
|
||||
+ deleted at this point, which is why it is not necessary
|
||||
+ to reset the flag here. */
|
||||
}
|
||||
|
||||
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
|
||||
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
|
||||
index 4b1ea7c4078ee947..ea286abaea0128d1 100644
|
||||
--- a/elf/get-dynamic-info.h
|
||||
+++ b/elf/get-dynamic-info.h
|
||||
@@ -163,6 +163,8 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
|
||||
{
|
||||
l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
|
||||
+ if (l->l_flags_1 & DF_1_NODELETE)
|
||||
+ l->l_nodelete = link_map_nodelete_pending;
|
||||
|
||||
/* Only DT_1_SUPPORTED_MASK bits are supported, and we would like
|
||||
to assert this, but we can't. Users have been setting
|
||||
diff --git a/elf/tst-dlopenfail.c b/elf/tst-dlopenfail.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..ce3140c899562ca8
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopenfail.c
|
||||
@@ -0,0 +1,79 @@
|
||||
+/* Test dlopen rollback after failures involving NODELETE objects (bug 20839).
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <dlfcn.h>
|
||||
+#include <errno.h>
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* This test uses libpthread as the canonical NODELETE module. If
|
||||
+ libpthread is no longer NODELETE because it has been merged into
|
||||
+ libc, the test needs to be updated. */
|
||||
+ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL);
|
||||
+
|
||||
+ /* This is expected to fail because of the missing dependency. */
|
||||
+ puts ("info: attempting to load tst-dlopenfailmod1.so");
|
||||
+ TEST_VERIFY (dlopen ("tst-dlopenfailmod1.so", RTLD_LAZY) == NULL);
|
||||
+ const char *message = dlerror ();
|
||||
+ TEST_COMPARE_STRING (message,
|
||||
+ "tst-dlopenfail-missingmod.so:"
|
||||
+ " cannot open shared object file:"
|
||||
+ " No such file or directory");
|
||||
+
|
||||
+ /* Do not probe for the presence of libpthread at this point because
|
||||
+ that might trigger relocation if bug 20839 is present, obscuring
|
||||
+ a subsequent crash. */
|
||||
+
|
||||
+ /* This is expected to succeed. */
|
||||
+ puts ("info: loading tst-dlopenfailmod2.so");
|
||||
+ void *handle = xdlopen ("tst-dlopenfailmod2.so", RTLD_NOW);
|
||||
+ xdlclose (handle);
|
||||
+
|
||||
+ /* libpthread should remain loaded. */
|
||||
+ TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_NOLOAD) != NULL);
|
||||
+ TEST_VERIFY (dlsym (NULL, "pthread_create") == NULL);
|
||||
+
|
||||
+ /* We can make libpthread global, and then the symbol should become
|
||||
+ available. */
|
||||
+ TEST_VERIFY (dlopen (LIBPTHREAD_SO, RTLD_LAZY | RTLD_GLOBAL) != NULL);
|
||||
+ TEST_VERIFY (dlsym (NULL, "pthread_create") != NULL);
|
||||
+
|
||||
+ /* sem_open is sufficiently complex to depend on relocations. */
|
||||
+ void *(*sem_open_ptr) (const char *, int flag, ...)
|
||||
+ = dlsym (NULL, "sem_open");
|
||||
+ if (sem_open_ptr == NULL)
|
||||
+ /* Hurd does not implement sem_open. */
|
||||
+ puts ("warning: sem_open not found, further testing not possible");
|
||||
+ else
|
||||
+ {
|
||||
+ errno = 0;
|
||||
+ TEST_VERIFY (sem_open_ptr ("/", 0) == NULL);
|
||||
+ TEST_COMPARE (errno, EINVAL);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopenfaillinkmod.c b/elf/tst-dlopenfaillinkmod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..3b14b02bc9a12c0b
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopenfaillinkmod.c
|
||||
@@ -0,0 +1,17 @@
|
||||
+/* Empty module with a soname which is not available at run time.
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
diff --git a/elf/tst-dlopenfailmod1.c b/elf/tst-dlopenfailmod1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..6ef48829899a5a64
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopenfailmod1.c
|
||||
@@ -0,0 +1,36 @@
|
||||
+/* Module which depends on two modules: one NODELETE, one missing.
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* Note: Due to the missing second module, this object cannot be
|
||||
+ loaded at run time. */
|
||||
+
|
||||
+#include <pthread.h>
|
||||
+#include <stdio.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Force linking against libpthread. */
|
||||
+void *pthread_create_reference = pthread_create;
|
||||
+
|
||||
+/* The constructor will never be executed because the module cannot be
|
||||
+ loaded. */
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("tst-dlopenfailmod1 constructor executed");
|
||||
+ _exit (1);
|
||||
+}
|
||||
diff --git a/elf/tst-dlopenfailmod2.c b/elf/tst-dlopenfailmod2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7d600386c13b98bd
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopenfailmod2.c
|
||||
@@ -0,0 +1,29 @@
|
||||
+/* Module which depends on on a NODELETE module, and can be loaded.
|
||||
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <pthread.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+/* Force linking against libpthread. */
|
||||
+void *pthread_create_reference = pthread_create;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlopenfailmod2.so constructor invoked");
|
||||
+}
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index 83b1c34b7b4db8f3..a277b77cad6b52b1 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -79,6 +79,21 @@ struct r_search_path_struct
|
||||
int malloced;
|
||||
};
|
||||
|
||||
+/* Type used by the l_nodelete member. */
|
||||
+enum link_map_nodelete
|
||||
+{
|
||||
+ /* This link map can be deallocated. */
|
||||
+ link_map_nodelete_inactive = 0, /* Zero-initialized in _dl_new_object. */
|
||||
+
|
||||
+ /* This link map cannot be deallocated. */
|
||||
+ link_map_nodelete_active,
|
||||
+
|
||||
+ /* This link map cannot be deallocated after dlopen has succeded.
|
||||
+ dlopen turns this into link_map_nodelete_active. dlclose treats
|
||||
+ this intermediate state as link_map_nodelete_active. */
|
||||
+ link_map_nodelete_pending,
|
||||
+};
|
||||
+
|
||||
|
||||
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||
members form a chain of all the shared objects loaded at startup.
|
||||
@@ -203,6 +218,11 @@ struct link_map
|
||||
freed, ie. not allocated with
|
||||
the dummy malloc in ld.so. */
|
||||
|
||||
+ /* Actually of type enum link_map_nodelete. Separate byte due to
|
||||
+ a read in add_dependency in elf/dl-lookup.c outside the loader
|
||||
+ lock. Only valid for l_type == lt_loaded. */
|
||||
+ unsigned char l_nodelete;
|
||||
+
|
||||
#include <link_map.h>
|
||||
|
||||
/* Collected information about own RPATH directories. */
|
@ -0,0 +1,104 @@
|
||||
commit a2e8aa0d9ea648068d8be52dd7b15f1b6a008e23
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Oct 31 19:30:19 2019 +0100
|
||||
|
||||
Block signals during the initial part of dlopen
|
||||
|
||||
Lazy binding in a signal handler that interrupts a dlopen sees
|
||||
intermediate dynamic linker state. This has likely been always
|
||||
unsafe, but with the new pending NODELETE state, this is clearly
|
||||
incorrect. Other threads are excluded via the loader lock, but the
|
||||
current thread is not. Blocking signals until right before ELF
|
||||
constructors run is the safe thing to do.
|
||||
|
||||
Change-Id: Iad079080ebe7442c13313ba11dc2797953faef35
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 79c6e4c8ed1c9dfa..25838b073ac1edaf 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <atomic.h>
|
||||
#include <libc-internal.h>
|
||||
#include <array_length.h>
|
||||
+#include <internal-signals.h>
|
||||
|
||||
#include <dl-dst.h>
|
||||
#include <dl-prop.h>
|
||||
@@ -52,6 +53,10 @@ struct dl_open_args
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
|
||||
+ /* Original signal mask. Used for unblocking signal handlers before
|
||||
+ running ELF constructors. */
|
||||
+ sigset_t original_signal_mask;
|
||||
+
|
||||
/* Original value of _ns_global_scope_pending_adds. Set by
|
||||
dl_open_worker. Only valid if nsid is a real namespace
|
||||
(non-negative). */
|
||||
@@ -524,12 +529,16 @@ dl_open_worker (void *a)
|
||||
if (new == NULL)
|
||||
{
|
||||
assert (mode & RTLD_NOLOAD);
|
||||
+ __libc_signal_restore_set (&args->original_signal_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (mode & __RTLD_SPROF))
|
||||
- /* This happens only if we load a DSO for 'sprof'. */
|
||||
- return;
|
||||
+ {
|
||||
+ /* This happens only if we load a DSO for 'sprof'. */
|
||||
+ __libc_signal_restore_set (&args->original_signal_mask);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
/* This object is directly loaded. */
|
||||
++new->l_direct_opencount;
|
||||
@@ -565,6 +574,7 @@ dl_open_worker (void *a)
|
||||
|
||||
assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
||||
|
||||
+ __libc_signal_restore_set (&args->original_signal_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -745,6 +755,10 @@ dl_open_worker (void *a)
|
||||
if (mode & RTLD_GLOBAL)
|
||||
add_to_global_resize (new);
|
||||
|
||||
+ /* Unblock signals. Data structures are now consistent, and
|
||||
+ application code may run. */
|
||||
+ __libc_signal_restore_set (&args->original_signal_mask);
|
||||
+
|
||||
/* Run the initializer functions of new objects. Temporarily
|
||||
disable the exception handler, so that lazy binding failures are
|
||||
fatal. */
|
||||
@@ -834,6 +848,10 @@ no more namespaces available for dlmopen()"));
|
||||
args.argv = argv;
|
||||
args.env = env;
|
||||
|
||||
+ /* Recursive lazy binding during manipulation of the dynamic loader
|
||||
+ structures may result in incorrect behavior. */
|
||||
+ __libc_signal_block_all (&args.original_signal_mask);
|
||||
+
|
||||
struct dl_exception exception;
|
||||
int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);
|
||||
|
||||
@@ -874,10 +892,16 @@ no more namespaces available for dlmopen()"));
|
||||
|
||||
_dl_close_worker (args.map, true);
|
||||
|
||||
+ /* Restore the signal mask. In the success case, this
|
||||
+ happens inside dl_open_worker. */
|
||||
+ __libc_signal_restore_set (&args.original_signal_mask);
|
||||
+
|
||||
/* All link_map_nodelete_pending objects should have been
|
||||
deleted at this point, which is why it is not necessary
|
||||
to reset the flag here. */
|
||||
}
|
||||
+ else
|
||||
+ __libc_signal_restore_set (&args.original_signal_mask);
|
||||
|
||||
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
|
||||
|
@ -0,0 +1,22 @@
|
||||
Please see the following bug for a complete summary:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1615608
|
||||
|
||||
Index: glibc-2.28/manual/startup.texi
|
||||
===================================================================
|
||||
--- glibc-2.28.orig/manual/startup.texi
|
||||
+++ glibc-2.28/manual/startup.texi
|
||||
@@ -1005,14 +1005,6 @@ This function actually terminates the pr
|
||||
intercept this signal; see @ref{Signal Handling}.
|
||||
@end deftypefun
|
||||
|
||||
-@c Put in by rms. Don't remove.
|
||||
-@cartouche
|
||||
-@strong{Future Change Warning:} Proposed Federal censorship regulations
|
||||
-may prohibit us from giving you information about the possibility of
|
||||
-calling this function. We would be required to say that this is not an
|
||||
-acceptable way of terminating a program.
|
||||
-@end cartouche
|
||||
-
|
||||
@node Termination Internals
|
||||
@subsection Termination Internals
|
||||
|
@ -0,0 +1,24 @@
|
||||
Patch by Hanataka Shinya <hanataka.shinya@gmail.com> from
|
||||
<https://sourceware.org/bugzilla/show_bug.cgi?id=24405>. Confirmed by TAMUKI
|
||||
Shoichi's patch in
|
||||
<https://sourceware.org/ml/libc-alpha/2019-04/msg00005.html>.
|
||||
|
||||
The official announcement by the Japanese Prime Minister in
|
||||
<https://www.kantei.go.jp/jp/tyoukanpress/201904/1_a.html> uses U+4EE4 U+548C
|
||||
as well.
|
||||
|
||||
diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP
|
||||
index 1fd2fee44b2879d9..30190b624856cc53 100644
|
||||
--- a/localedata/locales/ja_JP
|
||||
+++ b/localedata/locales/ja_JP
|
||||
@@ -14946,7 +14946,9 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>"
|
||||
|
||||
t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
|
||||
|
||||
-era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
|
||||
+era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
|
||||
+ "+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
|
||||
+ "+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
|
||||
"+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
|
||||
"+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
|
||||
"+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
|
@ -0,0 +1,254 @@
|
||||
commit 4b25485f03158959cff45379eecc1d73c7dcdd11
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Aug 10 11:19:26 2018 +0200
|
||||
|
||||
Linux: Rewrite __old_getdents64 [BZ #23497]
|
||||
|
||||
Commit 298d0e3129c0b5137f4989275b13fe30d0733c4d ("Consolidate Linux
|
||||
getdents{64} implementation") broke the implementation because it does
|
||||
not take into account struct offset differences.
|
||||
|
||||
The new implementation is close to the old one, before the
|
||||
consolidation, but has been cleaned up slightly.
|
||||
|
||||
(cherry picked from commit 690652882b499defb3d950dfeff8fe421d13cab5)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||||
index f71cc39c7e257a0a..773aaea0e980bdd6 100644
|
||||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||||
@@ -161,6 +161,7 @@ inhibit-glue = yes
|
||||
|
||||
ifeq ($(subdir),dirent)
|
||||
sysdep_routines += getdirentries getdirentries64
|
||||
+tests-internal += tst-readdir64-compat
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),nis)
|
||||
diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
|
||||
index 3bde0cf4f0226f95..bc140b5a7fac3040 100644
|
||||
--- a/sysdeps/unix/sysv/linux/getdents64.c
|
||||
+++ b/sysdeps/unix/sysv/linux/getdents64.c
|
||||
@@ -33,41 +33,80 @@ strong_alias (__getdents64, __getdents)
|
||||
# include <shlib-compat.h>
|
||||
|
||||
# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
|
||||
-# include <olddirent.h>
|
||||
+# include <olddirent.h>
|
||||
+# include <unistd.h>
|
||||
|
||||
-/* kernel definition of as of 3.2. */
|
||||
-struct compat_linux_dirent
|
||||
+static ssize_t
|
||||
+handle_overflow (int fd, __off64_t offset, ssize_t count)
|
||||
{
|
||||
- /* Both d_ino and d_off are compat_ulong_t which are defined in all
|
||||
- architectures as 'u32'. */
|
||||
- uint32_t d_ino;
|
||||
- uint32_t d_off;
|
||||
- unsigned short d_reclen;
|
||||
- char d_name[1];
|
||||
-};
|
||||
+ /* If this is the first entry in the buffer, we can report the
|
||||
+ error. */
|
||||
+ if (count == 0)
|
||||
+ {
|
||||
+ __set_errno (EOVERFLOW);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ /* Otherwise, seek to the overflowing entry, so that the next call
|
||||
+ will report the error, and return the data read so far.. */
|
||||
+ if (__lseek64 (fd, offset, SEEK_SET) != 0)
|
||||
+ return -1;
|
||||
+ return count;
|
||||
+}
|
||||
|
||||
ssize_t
|
||||
__old_getdents64 (int fd, char *buf, size_t nbytes)
|
||||
{
|
||||
- ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes);
|
||||
+ /* We do not move the individual directory entries. This is only
|
||||
+ possible if the target type (struct __old_dirent64) is smaller
|
||||
+ than the source type. */
|
||||
+ _Static_assert (offsetof (struct __old_dirent64, d_name)
|
||||
+ <= offsetof (struct dirent64, d_name),
|
||||
+ "__old_dirent64 is larger than dirent64");
|
||||
+ _Static_assert (__alignof__ (struct __old_dirent64)
|
||||
+ <= __alignof__ (struct dirent64),
|
||||
+ "alignment of __old_dirent64 is larger than dirent64");
|
||||
|
||||
- /* The kernel added the d_type value after the name. Change this now. */
|
||||
- if (retval != -1)
|
||||
+ ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
|
||||
+ if (retval > 0)
|
||||
{
|
||||
- union
|
||||
- {
|
||||
- struct compat_linux_dirent k;
|
||||
- struct dirent u;
|
||||
- } *kbuf = (void *) buf;
|
||||
-
|
||||
- while ((char *) kbuf < buf + retval)
|
||||
+ char *p = buf;
|
||||
+ char *end = buf + retval;
|
||||
+ while (p < end)
|
||||
{
|
||||
- char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1);
|
||||
- memmove (kbuf->u.d_name, kbuf->k.d_name,
|
||||
- strlen (kbuf->k.d_name) + 1);
|
||||
- kbuf->u.d_type = d_type;
|
||||
+ struct dirent64 *source = (struct dirent64 *) p;
|
||||
+
|
||||
+ /* Copy out the fixed-size data. */
|
||||
+ __ino_t ino = source->d_ino;
|
||||
+ __off64_t offset = source->d_off;
|
||||
+ unsigned int reclen = source->d_reclen;
|
||||
+ unsigned char type = source->d_type;
|
||||
+
|
||||
+ /* Check for ino_t overflow. */
|
||||
+ if (__glibc_unlikely (ino != source->d_ino))
|
||||
+ return handle_overflow (fd, offset, p - buf);
|
||||
+
|
||||
+ /* Convert to the target layout. Use a separate struct and
|
||||
+ memcpy to side-step aliasing issues. */
|
||||
+ struct __old_dirent64 result;
|
||||
+ result.d_ino = ino;
|
||||
+ result.d_off = offset;
|
||||
+ result.d_reclen = reclen;
|
||||
+ result.d_type = type;
|
||||
+
|
||||
+ /* Write the fixed-sized part of the result to the
|
||||
+ buffer. */
|
||||
+ size_t result_name_offset = offsetof (struct __old_dirent64, d_name);
|
||||
+ memcpy (p, &result, result_name_offset);
|
||||
+
|
||||
+ /* Adjust the position of the name if necessary. Copy
|
||||
+ everything until the end of the record, including the
|
||||
+ terminating NUL byte. */
|
||||
+ if (result_name_offset != offsetof (struct dirent64, d_name))
|
||||
+ memmove (p + result_name_offset, source->d_name,
|
||||
+ reclen - offsetof (struct dirent64, d_name));
|
||||
|
||||
- kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen);
|
||||
+ p += reclen;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..43c4a8477c7403c5
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
|
||||
@@ -0,0 +1,111 @@
|
||||
+/* Test readdir64 compatibility symbol.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <dirent.h>
|
||||
+#include <dlfcn.h>
|
||||
+#include <errno.h>
|
||||
+#include <shlib-compat.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+/* Copied from <olddirent.h>. */
|
||||
+struct __old_dirent64
|
||||
+ {
|
||||
+ __ino_t d_ino;
|
||||
+ __off64_t d_off;
|
||||
+ unsigned short int d_reclen;
|
||||
+ unsigned char d_type;
|
||||
+ char d_name[256];
|
||||
+ };
|
||||
+
|
||||
+typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *);
|
||||
+
|
||||
+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
|
||||
+struct __old_dirent64 *compat_readdir64 (DIR *);
|
||||
+compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1);
|
||||
+#endif
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
|
||||
+
|
||||
+ /* Directory stream using the non-compat readdir64 symbol. The test
|
||||
+ checks against this. */
|
||||
+ DIR *dir_reference = opendir (".");
|
||||
+ TEST_VERIFY_EXIT (dir_reference != NULL);
|
||||
+ DIR *dir_test = opendir (".");
|
||||
+ TEST_VERIFY_EXIT (dir_test != NULL);
|
||||
+
|
||||
+ /* This loop assumes that the enumeration order is consistent for
|
||||
+ two different handles. Nothing should write to the current
|
||||
+ directory (in the source tree) while this test runs, so there
|
||||
+ should not be any difference due to races. */
|
||||
+ size_t count = 0;
|
||||
+ while (true)
|
||||
+ {
|
||||
+ errno = 0;
|
||||
+ struct dirent64 *entry_reference = readdir64 (dir_reference);
|
||||
+ if (entry_reference == NULL && errno != 0)
|
||||
+ FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count);
|
||||
+ struct __old_dirent64 *entry_test = compat_readdir64 (dir_test);
|
||||
+ if (entry_reference == NULL)
|
||||
+ {
|
||||
+ if (errno == EOVERFLOW)
|
||||
+ {
|
||||
+ TEST_VERIFY (entry_reference->d_ino
|
||||
+ != (__ino_t) entry_reference->d_ino);
|
||||
+ printf ("info: inode number overflow at entry %zu\n", count);
|
||||
+ break;
|
||||
+ }
|
||||
+ if (errno != 0)
|
||||
+ FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count);
|
||||
+ }
|
||||
+
|
||||
+ /* Check that both streams end at the same time. */
|
||||
+ if (entry_reference == NULL)
|
||||
+ {
|
||||
+ TEST_VERIFY (entry_test == NULL);
|
||||
+ break;
|
||||
+ }
|
||||
+ else
|
||||
+ TEST_VERIFY_EXIT (entry_test != NULL);
|
||||
+
|
||||
+ /* Check that the entries are the same. */
|
||||
+ TEST_COMPARE_BLOB (entry_reference->d_name,
|
||||
+ strlen (entry_reference->d_name),
|
||||
+ entry_test->d_name, strlen (entry_test->d_name));
|
||||
+ TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino);
|
||||
+ TEST_COMPARE (entry_reference->d_off, entry_test->d_off);
|
||||
+ TEST_COMPARE (entry_reference->d_type, entry_test->d_type);
|
||||
+ TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen);
|
||||
+
|
||||
+ ++count;
|
||||
+ }
|
||||
+ printf ("info: %zu directory entries found\n", count);
|
||||
+ TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */
|
||||
+
|
||||
+ TEST_COMPARE (closedir (dir_test), 0);
|
||||
+ TEST_COMPARE (closedir (dir_reference), 0);
|
||||
+#endif
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,154 @@
|
||||
commit d524fa6c35e675eedbd8fe6cdf4db0b49c658026
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Thu Nov 8 10:06:58 2018 -0800
|
||||
|
||||
Check multiple NT_GNU_PROPERTY_TYPE_0 notes [BZ #23509]
|
||||
|
||||
Linkers group input note sections with the same name into one output
|
||||
note section with the same name. One output note section is placed in
|
||||
one PT_NOTE segment. Since new linkers merge input .note.gnu.property
|
||||
sections into one output .note.gnu.property section, there is only
|
||||
one NT_GNU_PROPERTY_TYPE_0 note in one PT_NOTE segment with new linkers.
|
||||
Since older linkers treat input .note.gnu.property section as a generic
|
||||
note section and just concatenate all input .note.gnu.property sections
|
||||
into one output .note.gnu.property section without merging them, we may
|
||||
see multiple NT_GNU_PROPERTY_TYPE_0 notes in one PT_NOTE segment with
|
||||
older linkers.
|
||||
|
||||
When an older linker is used to created the program on CET-enabled OS,
|
||||
the linker output has a single .note.gnu.property section with multiple
|
||||
NT_GNU_PROPERTY_TYPE_0 notes, some of which have IBT and SHSTK enable
|
||||
bits set even if the program isn't CET enabled. Such programs will
|
||||
crash on CET-enabled machines. This patch updates the note parser:
|
||||
|
||||
1. Skip note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed.
|
||||
2. Check multiple NT_GNU_PROPERTY_TYPE_0 notes.
|
||||
|
||||
[BZ #23509]
|
||||
* sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip
|
||||
note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed.
|
||||
Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note.
|
||||
Check multiple NT_GNU_PROPERTY_TYPE_0 notes.
|
||||
* sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add
|
||||
lc_unknown.
|
||||
|
||||
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
|
||||
index 26c3131ac5e2d080..9ab890d12bb99133 100644
|
||||
--- a/sysdeps/x86/dl-prop.h
|
||||
+++ b/sysdeps/x86/dl-prop.h
|
||||
@@ -49,6 +49,10 @@ _dl_process_cet_property_note (struct link_map *l,
|
||||
const ElfW(Addr) align)
|
||||
{
|
||||
#if CET_ENABLED
|
||||
+ /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */
|
||||
+ if (l->l_cet != lc_unknown)
|
||||
+ return;
|
||||
+
|
||||
/* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
|
||||
32-bit objects and to 8 bytes in 64-bit objects. Skip notes
|
||||
with incorrect alignment. */
|
||||
@@ -57,6 +61,9 @@ _dl_process_cet_property_note (struct link_map *l,
|
||||
|
||||
const ElfW(Addr) start = (ElfW(Addr)) note;
|
||||
|
||||
+ unsigned int feature_1 = 0;
|
||||
+ unsigned int last_type = 0;
|
||||
+
|
||||
while ((ElfW(Addr)) (note + 1) - start < size)
|
||||
{
|
||||
/* Find the NT_GNU_PROPERTY_TYPE_0 note. */
|
||||
@@ -64,10 +71,18 @@ _dl_process_cet_property_note (struct link_map *l,
|
||||
&& note->n_type == NT_GNU_PROPERTY_TYPE_0
|
||||
&& memcmp (note + 1, "GNU", 4) == 0)
|
||||
{
|
||||
+ /* Stop if we see more than one GNU property note which may
|
||||
+ be generated by the older linker. */
|
||||
+ if (l->l_cet != lc_unknown)
|
||||
+ return;
|
||||
+
|
||||
+ /* Check CET status now. */
|
||||
+ l->l_cet = lc_none;
|
||||
+
|
||||
/* Check for invalid property. */
|
||||
if (note->n_descsz < 8
|
||||
|| (note->n_descsz % sizeof (ElfW(Addr))) != 0)
|
||||
- break;
|
||||
+ return;
|
||||
|
||||
/* Start and end of property array. */
|
||||
unsigned char *ptr = (unsigned char *) (note + 1) + 4;
|
||||
@@ -78,9 +93,15 @@ _dl_process_cet_property_note (struct link_map *l,
|
||||
unsigned int type = *(unsigned int *) ptr;
|
||||
unsigned int datasz = *(unsigned int *) (ptr + 4);
|
||||
|
||||
+ /* Property type must be in ascending order. */
|
||||
+ if (type < last_type)
|
||||
+ return;
|
||||
+
|
||||
ptr += 8;
|
||||
if ((ptr + datasz) > ptr_end)
|
||||
- break;
|
||||
+ return;
|
||||
+
|
||||
+ last_type = type;
|
||||
|
||||
if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
|
||||
{
|
||||
@@ -89,14 +110,18 @@ _dl_process_cet_property_note (struct link_map *l,
|
||||
we stop the search regardless if its size is correct
|
||||
or not. There is no point to continue if this note
|
||||
is ill-formed. */
|
||||
- if (datasz == 4)
|
||||
- {
|
||||
- unsigned int feature_1 = *(unsigned int *) ptr;
|
||||
- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
|
||||
- l->l_cet |= lc_ibt;
|
||||
- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
|
||||
- l->l_cet |= lc_shstk;
|
||||
- }
|
||||
+ if (datasz != 4)
|
||||
+ return;
|
||||
+
|
||||
+ feature_1 = *(unsigned int *) ptr;
|
||||
+
|
||||
+ /* Keep searching for the next GNU property note
|
||||
+ generated by the older linker. */
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (type > GNU_PROPERTY_X86_FEATURE_1_AND)
|
||||
+ {
|
||||
+ /* Stop since property type is in ascending order. */
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,6 +137,12 @@ _dl_process_cet_property_note (struct link_map *l,
|
||||
+ ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
|
||||
align));
|
||||
}
|
||||
+
|
||||
+ /* We get here only if there is one or no GNU property note. */
|
||||
+ if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
|
||||
+ l->l_cet |= lc_ibt;
|
||||
+ if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
|
||||
+ l->l_cet |= lc_shstk;
|
||||
#endif
|
||||
}
|
||||
|
||||
diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h
|
||||
index ef1206a9d2396a6f..9367ed08896794a4 100644
|
||||
--- a/sysdeps/x86/link_map.h
|
||||
+++ b/sysdeps/x86/link_map.h
|
||||
@@ -19,8 +19,9 @@
|
||||
/* If this object is enabled with CET. */
|
||||
enum
|
||||
{
|
||||
- lc_none = 0, /* Not enabled with CET. */
|
||||
- lc_ibt = 1 << 0, /* Enabled with IBT. */
|
||||
- lc_shstk = 1 << 1, /* Enabled with STSHK. */
|
||||
+ lc_unknown = 0, /* Unknown CET status. */
|
||||
+ lc_none = 1 << 0, /* Not enabled with CET. */
|
||||
+ lc_ibt = 1 << 1, /* Enabled with IBT. */
|
||||
+ lc_shstk = 1 << 2, /* Enabled with STSHK. */
|
||||
lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */
|
||||
- } l_cet:2;
|
||||
+ } l_cet:3;
|
@ -0,0 +1,28 @@
|
||||
commit d05b05d1570ba3ae354a2f5a3cfeefb373b09979
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Aug 13 14:28:07 2018 +0200
|
||||
|
||||
error, error_at_line: Add missing va_end calls
|
||||
|
||||
(cherry picked from commit b7b52b9dec337a08a89bc67638773be652eba332)
|
||||
|
||||
diff --git a/misc/error.c b/misc/error.c
|
||||
index b4e8b6c93886b737..03378e2f2aa6251e 100644
|
||||
--- a/misc/error.c
|
||||
+++ b/misc/error.c
|
||||
@@ -319,6 +319,7 @@ error (int status, int errnum, const char *message, ...)
|
||||
|
||||
va_start (args, message);
|
||||
error_tail (status, errnum, message, args);
|
||||
+ va_end (args);
|
||||
|
||||
#ifdef _LIBC
|
||||
_IO_funlockfile (stderr);
|
||||
@@ -390,6 +391,7 @@ error_at_line (int status, int errnum, const char *file_name,
|
||||
|
||||
va_start (args, message);
|
||||
error_tail (status, errnum, message, args);
|
||||
+ va_end (args);
|
||||
|
||||
#ifdef _LIBC
|
||||
_IO_funlockfile (stderr);
|
@ -0,0 +1,35 @@
|
||||
commit bfcfa22589f2b4277a65e60c6b736b6bbfbd87d0
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Aug 14 10:51:07 2018 +0200
|
||||
|
||||
nscd: Deallocate existing user names in file parser
|
||||
|
||||
This avoids a theoretical memory leak (theoretical because it depends on
|
||||
multiple server-user/stat-user directives in the configuration file).
|
||||
|
||||
(cherry picked from commit 2d7acfac3ebf266dcbc82d0d6cc576f626953a03)
|
||||
|
||||
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
|
||||
index 265a02434dd26c29..7293b795b6bcf71e 100644
|
||||
--- a/nscd/nscd_conf.c
|
||||
+++ b/nscd/nscd_conf.c
|
||||
@@ -190,7 +190,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
|
||||
if (!arg1)
|
||||
error (0, 0, _("Must specify user name for server-user option"));
|
||||
else
|
||||
- server_user = xstrdup (arg1);
|
||||
+ {
|
||||
+ free ((char *) server_user);
|
||||
+ server_user = xstrdup (arg1);
|
||||
+ }
|
||||
}
|
||||
else if (strcmp (entry, "stat-user") == 0)
|
||||
{
|
||||
@@ -198,6 +201,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
|
||||
error (0, 0, _("Must specify user name for stat-user option"));
|
||||
else
|
||||
{
|
||||
+ free ((char *) stat_user);
|
||||
stat_user = xstrdup (arg1);
|
||||
|
||||
struct passwd *pw = getpwnam (stat_user);
|
@ -0,0 +1,306 @@
|
||||
commit 2f498f3d140ab5152bd784df2be7af7d9c5e63ed
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Aug 14 10:57:48 2018 +0200
|
||||
|
||||
nss_files: Fix file stream leak in aliases lookup [BZ #23521]
|
||||
|
||||
In order to get a clean test case, it was necessary to fix partially
|
||||
fixed bug 23522 as well.
|
||||
|
||||
(cherry picked from commit e95c6f61920a0f9237cfb292fa44ad500e1df09b)
|
||||
|
||||
diff --git a/nss/Makefile b/nss/Makefile
|
||||
index 66fac7f5b8a4c0d8..5209fc0456dd6786 100644
|
||||
--- a/nss/Makefile
|
||||
+++ b/nss/Makefile
|
||||
@@ -65,6 +65,7 @@ ifeq (yes,$(build-shared))
|
||||
tests += tst-nss-files-hosts-erange
|
||||
tests += tst-nss-files-hosts-multi
|
||||
tests += tst-nss-files-hosts-getent
|
||||
+tests += tst-nss-files-alias-leak
|
||||
endif
|
||||
|
||||
# If we have a thread library then we can test cancellation against
|
||||
@@ -171,3 +172,5 @@ endif
|
||||
$(objpfx)tst-nss-files-hosts-erange: $(libdl)
|
||||
$(objpfx)tst-nss-files-hosts-multi: $(libdl)
|
||||
$(objpfx)tst-nss-files-hosts-getent: $(libdl)
|
||||
+$(objpfx)tst-nss-files-alias-leak: $(libdl)
|
||||
+$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
|
||||
diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c
|
||||
index cfd34b66b921bbff..35b0bfc5d2479ab6 100644
|
||||
--- a/nss/nss_files/files-alias.c
|
||||
+++ b/nss/nss_files/files-alias.c
|
||||
@@ -221,6 +221,13 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result,
|
||||
{
|
||||
while (! feof_unlocked (listfile))
|
||||
{
|
||||
+ if (room_left < 2)
|
||||
+ {
|
||||
+ free (old_line);
|
||||
+ fclose (listfile);
|
||||
+ goto no_more_room;
|
||||
+ }
|
||||
+
|
||||
first_unused[room_left - 1] = '\xff';
|
||||
line = fgets_unlocked (first_unused, room_left,
|
||||
listfile);
|
||||
@@ -229,6 +236,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result,
|
||||
if (first_unused[room_left - 1] != '\xff')
|
||||
{
|
||||
free (old_line);
|
||||
+ fclose (listfile);
|
||||
goto no_more_room;
|
||||
}
|
||||
|
||||
@@ -256,6 +264,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result,
|
||||
+ __alignof__ (char *)))
|
||||
{
|
||||
free (old_line);
|
||||
+ fclose (listfile);
|
||||
goto no_more_room;
|
||||
}
|
||||
room_left -= ((first_unused - cp)
|
||||
diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..26d38e2dba1ddaf3
|
||||
--- /dev/null
|
||||
+++ b/nss/tst-nss-files-alias-leak.c
|
||||
@@ -0,0 +1,237 @@
|
||||
+/* Check for file descriptor leak in alias :include: processing (bug 23521).
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <aliases.h>
|
||||
+#include <array_length.h>
|
||||
+#include <dlfcn.h>
|
||||
+#include <errno.h>
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <nss.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+static struct support_chroot *chroot_env;
|
||||
+
|
||||
+/* Number of the aliases for the "many" user. This must be large
|
||||
+ enough to trigger reallocation for the pointer array, but result in
|
||||
+ answers below the maximum size tried in do_test. */
|
||||
+enum { many_aliases = 30 };
|
||||
+
|
||||
+static void
|
||||
+prepare (int argc, char **argv)
|
||||
+{
|
||||
+ chroot_env = support_chroot_create
|
||||
+ ((struct support_chroot_configuration) { } );
|
||||
+
|
||||
+ char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot);
|
||||
+ add_temp_file (path);
|
||||
+ support_write_file_string
|
||||
+ (path,
|
||||
+ "user1: :include:/etc/aliases.user1\n"
|
||||
+ "user2: :include:/etc/aliases.user2\n"
|
||||
+ "comment: comment1, :include:/etc/aliases.comment\n"
|
||||
+ "many: :include:/etc/aliases.many\n");
|
||||
+ free (path);
|
||||
+
|
||||
+ path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot);
|
||||
+ add_temp_file (path);
|
||||
+ support_write_file_string (path, "alias1\n");
|
||||
+ free (path);
|
||||
+
|
||||
+ path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot);
|
||||
+ add_temp_file (path);
|
||||
+ support_write_file_string (path, "alias1a, alias2\n");
|
||||
+ free (path);
|
||||
+
|
||||
+ path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot);
|
||||
+ add_temp_file (path);
|
||||
+ support_write_file_string
|
||||
+ (path,
|
||||
+ /* The line must be longer than the line with the :include:
|
||||
+ directive in /etc/aliases. */
|
||||
+ "# Long line. ##############################################\n"
|
||||
+ "comment2\n");
|
||||
+ free (path);
|
||||
+
|
||||
+ path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot);
|
||||
+ add_temp_file (path);
|
||||
+ FILE *fp = xfopen (path, "w");
|
||||
+ for (int i = 0; i < many_aliases; ++i)
|
||||
+ fprintf (fp, "a%d\n", i);
|
||||
+ TEST_VERIFY_EXIT (! ferror (fp));
|
||||
+ xfclose (fp);
|
||||
+ free (path);
|
||||
+}
|
||||
+
|
||||
+/* The names of the users to test. */
|
||||
+static const char *users[] = { "user1", "user2", "comment", "many" };
|
||||
+
|
||||
+static void
|
||||
+check_aliases (int id, const struct aliasent *e)
|
||||
+{
|
||||
+ TEST_VERIFY_EXIT (id >= 0 || id < array_length (users));
|
||||
+ const char *name = users[id];
|
||||
+ TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name),
|
||||
+ name, strlen (name));
|
||||
+
|
||||
+ switch (id)
|
||||
+ {
|
||||
+ case 0:
|
||||
+ TEST_COMPARE (e->alias_members_len, 1);
|
||||
+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
|
||||
+ "alias1", strlen ("alias1"));
|
||||
+ break;
|
||||
+
|
||||
+ case 1:
|
||||
+ TEST_COMPARE (e->alias_members_len, 2);
|
||||
+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
|
||||
+ "alias1a", strlen ("alias1a"));
|
||||
+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
|
||||
+ "alias2", strlen ("alias2"));
|
||||
+ break;
|
||||
+
|
||||
+ case 2:
|
||||
+ TEST_COMPARE (e->alias_members_len, 2);
|
||||
+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
|
||||
+ "comment1", strlen ("comment1"));
|
||||
+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
|
||||
+ "comment2", strlen ("comment2"));
|
||||
+ break;
|
||||
+
|
||||
+ case 3:
|
||||
+ TEST_COMPARE (e->alias_members_len, many_aliases);
|
||||
+ for (int i = 0; i < e->alias_members_len; ++i)
|
||||
+ {
|
||||
+ char alias[30];
|
||||
+ int len = snprintf (alias, sizeof (alias), "a%d", i);
|
||||
+ TEST_VERIFY_EXIT (len > 0);
|
||||
+ TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]),
|
||||
+ alias, len);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Make sure we don't try to load the module in the chroot. */
|
||||
+ if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL)
|
||||
+ FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ());
|
||||
+
|
||||
+ /* Some of these descriptors will become unavailable if there is a
|
||||
+ file descriptor leak. 10 is chosen somewhat arbitrarily. The
|
||||
+ array must be longer than the number of files opened by nss_files
|
||||
+ at the same time (currently that number is 2). */
|
||||
+ int next_descriptors[10];
|
||||
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
|
||||
+ {
|
||||
+ next_descriptors[i] = dup (0);
|
||||
+ TEST_VERIFY_EXIT (next_descriptors[i] > 0);
|
||||
+ }
|
||||
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
|
||||
+ xclose (next_descriptors[i]);
|
||||
+
|
||||
+ support_become_root ();
|
||||
+ if (!support_can_chroot ())
|
||||
+ return EXIT_UNSUPPORTED;
|
||||
+
|
||||
+ __nss_configure_lookup ("aliases", "files");
|
||||
+
|
||||
+ xchroot (chroot_env->path_chroot);
|
||||
+
|
||||
+ /* Attempt various buffer sizes. If the operation succeeds, we
|
||||
+ expect correct data. */
|
||||
+ for (int id = 0; id < array_length (users); ++id)
|
||||
+ {
|
||||
+ bool found = false;
|
||||
+ for (size_t size = 1; size <= 1000; ++size)
|
||||
+ {
|
||||
+ void *buffer = malloc (size);
|
||||
+ struct aliasent result;
|
||||
+ struct aliasent *res;
|
||||
+ errno = EINVAL;
|
||||
+ int ret = getaliasbyname_r (users[id], &result, buffer, size, &res);
|
||||
+ if (ret == 0)
|
||||
+ {
|
||||
+ if (res != NULL)
|
||||
+ {
|
||||
+ found = true;
|
||||
+ check_aliases (id, res);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: failed lookup for user \"%s\", size %zu\n",
|
||||
+ users[id], size);
|
||||
+ }
|
||||
+ }
|
||||
+ else if (ret != ERANGE)
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: invalid return code %d (user \%s\", size %zu)\n",
|
||||
+ ret, users[id], size);
|
||||
+ }
|
||||
+ free (buffer);
|
||||
+
|
||||
+ /* Make sure that we did not have a file descriptor leak. */
|
||||
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
|
||||
+ {
|
||||
+ int new_fd = dup (0);
|
||||
+ if (new_fd != next_descriptors[i])
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: descriptor %d at index %zu leaked"
|
||||
+ " (user \"%s\", size %zu)\n",
|
||||
+ next_descriptors[i], i, users[id], size);
|
||||
+
|
||||
+ /* Close unexpected descriptor, the leak probing
|
||||
+ descriptors, and the leaked descriptor
|
||||
+ next_descriptors[i]. */
|
||||
+ xclose (new_fd);
|
||||
+ for (size_t j = 0; j <= i; ++j)
|
||||
+ xclose (next_descriptors[j]);
|
||||
+ goto next_size;
|
||||
+ }
|
||||
+ }
|
||||
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
|
||||
+ xclose (next_descriptors[i]);
|
||||
+
|
||||
+ next_size:
|
||||
+ ;
|
||||
+ }
|
||||
+ if (!found)
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: user %s not found\n", users[id]);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ support_chroot_free (chroot_env);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#define PREPARE prepare
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,27 @@
|
||||
commit aa8a3e4cdef20c50cb20f008864fff05cbfbdf29
|
||||
Author: Martin Kuchta <martin.kuchta@netapp.com>
|
||||
Date: Mon Aug 27 18:54:46 2018 +0200
|
||||
|
||||
pthread_cond_broadcast: Fix waiters-after-spinning case [BZ #23538]
|
||||
|
||||
(cherry picked from commit 99ea93ca31795469d2a1f1570f17a5c39c2eb7e2)
|
||||
|
||||
diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c
|
||||
index 8e425eb01eceabec..479e54febb417675 100644
|
||||
--- a/nptl/pthread_cond_common.c
|
||||
+++ b/nptl/pthread_cond_common.c
|
||||
@@ -405,8 +405,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq,
|
||||
{
|
||||
/* There is still a waiter after spinning. Set the wake-request
|
||||
flag and block. Relaxed MO is fine because this is just about
|
||||
- this futex word. */
|
||||
- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1);
|
||||
+ this futex word.
|
||||
+
|
||||
+ Update r to include the set wake-request flag so that the upcoming
|
||||
+ futex_wait only blocks if the flag is still set (otherwise, we'd
|
||||
+ violate the basic client-side futex protocol). */
|
||||
+ r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1;
|
||||
|
||||
if ((r >> 1) > 0)
|
||||
futex_wait_simple (cond->__data.__g_refs + g1, r, private);
|
@ -0,0 +1,41 @@
|
||||
commit 58559f14437d2aa71753a29fed435efa06aa4576
|
||||
Author: Paul Eggert <eggert@cs.ucla.edu>
|
||||
Date: Tue Aug 28 21:54:28 2018 +0200
|
||||
|
||||
regex: fix uninitialized memory access
|
||||
|
||||
I introduced this bug into gnulib in commit
|
||||
8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10;
|
||||
eventually it was merged into glibc. The bug was found by
|
||||
project-repo <bugs@feusi.co> and reported here:
|
||||
https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html
|
||||
Diagnosis and draft fix reported by Assaf Gordon here:
|
||||
https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html
|
||||
https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html
|
||||
* posix/regex_internal.c (build_wcs_upper_buffer):
|
||||
Fix bug when mbrtowc returns 0.
|
||||
|
||||
(cherry picked from commit bc680b336971305cb39896b30d72dc7101b62242)
|
||||
|
||||
diff --git a/posix/regex_internal.c b/posix/regex_internal.c
|
||||
index 7f0083b918de6530..b10588f1ccbb1992 100644
|
||||
--- a/posix/regex_internal.c
|
||||
+++ b/posix/regex_internal.c
|
||||
@@ -317,7 +317,7 @@ build_wcs_upper_buffer (re_string_t *pstr)
|
||||
mbclen = __mbrtowc (&wc,
|
||||
((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
|
||||
+ byte_idx), remain_len, &pstr->cur_state);
|
||||
- if (BE (mbclen < (size_t) -2, 1))
|
||||
+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1))
|
||||
{
|
||||
wchar_t wcu = __towupper (wc);
|
||||
if (wcu != wc)
|
||||
@@ -386,7 +386,7 @@ build_wcs_upper_buffer (re_string_t *pstr)
|
||||
else
|
||||
p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
|
||||
mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
|
||||
- if (BE (mbclen < (size_t) -2, 1))
|
||||
+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1))
|
||||
{
|
||||
wchar_t wcu = __towupper (wc);
|
||||
if (wcu != wc)
|
@ -0,0 +1,226 @@
|
||||
commit 0b79004569e5ce1669136b8c41564c3809730f15
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Aug 28 12:57:46 2018 +0200
|
||||
|
||||
regex: Add test tst-regcomp-truncated [BZ #23578]
|
||||
|
||||
(cherry picked from commit 761404b74d9853ce1608195e24f25b78a910591a)
|
||||
|
||||
diff --git a/posix/Makefile b/posix/Makefile
|
||||
index 00c62841a282f15a..83162123f9c927a0 100644
|
||||
--- a/posix/Makefile
|
||||
+++ b/posix/Makefile
|
||||
@@ -96,7 +96,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \
|
||||
tst-posix_fadvise tst-posix_fadvise64 \
|
||||
tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
|
||||
tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
|
||||
- bug-regex38
|
||||
+ bug-regex38 tst-regcomp-truncated
|
||||
tests-internal := bug-regex5 bug-regex20 bug-regex33 \
|
||||
tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
|
||||
tst-glob_lstat_compat tst-spawn4-compat
|
||||
@@ -194,6 +194,7 @@ $(objpfx)tst-regex2.out: $(gen-locales)
|
||||
$(objpfx)tst-regexloc.out: $(gen-locales)
|
||||
$(objpfx)tst-rxspencer.out: $(gen-locales)
|
||||
$(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales)
|
||||
+$(objpfx)tst-regcomp-truncated.out: $(gen-locales)
|
||||
endif
|
||||
|
||||
# If we will use the generic uname implementation, we must figure out what
|
||||
diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..a4a1581bbc2b39eb
|
||||
--- /dev/null
|
||||
+++ b/posix/tst-regcomp-truncated.c
|
||||
@@ -0,0 +1,191 @@
|
||||
+/* Test compilation of truncated regular expressions.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* This test constructs various patterns in an attempt to trigger
|
||||
+ over-reading the regular expression compiler, such as bug
|
||||
+ 23578. */
|
||||
+
|
||||
+#include <array_length.h>
|
||||
+#include <errno.h>
|
||||
+#include <locale.h>
|
||||
+#include <regex.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/next_to_fault.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <wchar.h>
|
||||
+
|
||||
+/* Locales to test. */
|
||||
+static const char locales[][17] =
|
||||
+ {
|
||||
+ "C",
|
||||
+ "en_US.UTF-8",
|
||||
+ "de_DE.ISO-8859-1",
|
||||
+ };
|
||||
+
|
||||
+/* Syntax options. Will be combined with other flags. */
|
||||
+static const reg_syntax_t syntaxes[] =
|
||||
+ {
|
||||
+ RE_SYNTAX_EMACS,
|
||||
+ RE_SYNTAX_AWK,
|
||||
+ RE_SYNTAX_GNU_AWK,
|
||||
+ RE_SYNTAX_POSIX_AWK,
|
||||
+ RE_SYNTAX_GREP,
|
||||
+ RE_SYNTAX_EGREP,
|
||||
+ RE_SYNTAX_POSIX_EGREP,
|
||||
+ RE_SYNTAX_POSIX_BASIC,
|
||||
+ RE_SYNTAX_POSIX_EXTENDED,
|
||||
+ RE_SYNTAX_POSIX_MINIMAL_EXTENDED,
|
||||
+ };
|
||||
+
|
||||
+/* Trailing characters placed after the initial character. */
|
||||
+static const char trailing_strings[][4] =
|
||||
+ {
|
||||
+ "",
|
||||
+ "[",
|
||||
+ "\\",
|
||||
+ "[\\",
|
||||
+ "(",
|
||||
+ "(\\",
|
||||
+ "\\(",
|
||||
+ };
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Staging buffer for the constructed regular expression. */
|
||||
+ char buffer[16];
|
||||
+
|
||||
+ /* Allocation used to detect over-reading by the regular expression
|
||||
+ compiler. */
|
||||
+ struct support_next_to_fault ntf
|
||||
+ = support_next_to_fault_allocate (sizeof (buffer));
|
||||
+
|
||||
+ /* Arbitrary Unicode codepoint at which we stop generating
|
||||
+ characters. We do not probe the whole range because that would
|
||||
+ take too long due to combinatorical exploision as the result of
|
||||
+ combination with other flags. */
|
||||
+ static const wchar_t last_character = 0xfff;
|
||||
+
|
||||
+ for (size_t locale_idx = 0; locale_idx < array_length (locales);
|
||||
+ ++ locale_idx)
|
||||
+ {
|
||||
+ if (setlocale (LC_ALL, locales[locale_idx]) == NULL)
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]);
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (test_verbose > 0)
|
||||
+ printf ("info: testing locale \"%s\"\n", locales[locale_idx]);
|
||||
+
|
||||
+ for (wchar_t wc = 0; wc <= last_character; ++wc)
|
||||
+ {
|
||||
+ char *after_wc;
|
||||
+ if (wc == 0)
|
||||
+ {
|
||||
+ /* wcrtomb treats L'\0' in a special way. */
|
||||
+ *buffer = '\0';
|
||||
+ after_wc = &buffer[1];
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ mbstate_t ps = { };
|
||||
+ size_t ret = wcrtomb (buffer, wc, &ps);
|
||||
+ if (ret == (size_t) -1)
|
||||
+ {
|
||||
+ /* EILSEQ means that the target character set
|
||||
+ cannot encode the character. */
|
||||
+ if (errno != EILSEQ)
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: wcrtomb (0x%x) failed: %m\n",
|
||||
+ (unsigned) wc);
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ TEST_VERIFY_EXIT (ret != 0);
|
||||
+ after_wc = &buffer[ret];
|
||||
+ }
|
||||
+
|
||||
+ for (size_t trailing_idx = 0;
|
||||
+ trailing_idx < array_length (trailing_strings);
|
||||
+ ++trailing_idx)
|
||||
+ {
|
||||
+ char *after_trailing
|
||||
+ = stpcpy (after_wc, trailing_strings[trailing_idx]);
|
||||
+
|
||||
+ for (int do_nul = 0; do_nul < 2; ++do_nul)
|
||||
+ {
|
||||
+ char *after_nul;
|
||||
+ if (do_nul)
|
||||
+ {
|
||||
+ *after_trailing = '\0';
|
||||
+ after_nul = &after_trailing[1];
|
||||
+ }
|
||||
+ else
|
||||
+ after_nul = after_trailing;
|
||||
+
|
||||
+ size_t length = after_nul - buffer;
|
||||
+
|
||||
+ /* Make sure that the faulting region starts
|
||||
+ after the used portion of the buffer. */
|
||||
+ char *ntf_start = ntf.buffer + sizeof (buffer) - length;
|
||||
+ memcpy (ntf_start, buffer, length);
|
||||
+
|
||||
+ for (const reg_syntax_t *psyntax = syntaxes;
|
||||
+ psyntax < array_end (syntaxes); ++psyntax)
|
||||
+ for (int do_icase = 0; do_icase < 2; ++do_icase)
|
||||
+ {
|
||||
+ re_syntax_options = *psyntax;
|
||||
+ if (do_icase)
|
||||
+ re_syntax_options |= RE_ICASE;
|
||||
+
|
||||
+ regex_t reg;
|
||||
+ memset (®, 0, sizeof (reg));
|
||||
+ const char *msg = re_compile_pattern
|
||||
+ (ntf_start, length, ®);
|
||||
+ if (msg != NULL)
|
||||
+ {
|
||||
+ if (test_verbose > 0)
|
||||
+ {
|
||||
+ char *quoted = support_quote_blob
|
||||
+ (buffer, length);
|
||||
+ printf ("info: compilation failed for pattern"
|
||||
+ " \"%s\", syntax 0x%lx: %s\n",
|
||||
+ quoted, re_syntax_options, msg);
|
||||
+ free (quoted);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ regfree (®);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ support_next_to_fault_free (&ntf);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,34 @@
|
||||
commit 3a67c72c1512f778304a5644dea2fcf5bdece274
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Thu Sep 27 12:37:06 2018 +0200
|
||||
|
||||
Fix stack overflow in tst-setcontext9 (bug 23717)
|
||||
|
||||
The function f1a, executed on a stack of size 32k, allocates an object of
|
||||
size 32k on the stack. Make the stack variables static to reduce
|
||||
excessive stack usage.
|
||||
|
||||
(cherry picked from commit f841c97e515a1673485a2b12b3c280073d737890)
|
||||
|
||||
diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c
|
||||
index db8355766ca7b906..009928235dd5987e 100644
|
||||
--- a/stdlib/tst-setcontext9.c
|
||||
+++ b/stdlib/tst-setcontext9.c
|
||||
@@ -58,7 +58,7 @@ f1b (void)
|
||||
static void
|
||||
f1a (void)
|
||||
{
|
||||
- char st2[32768];
|
||||
+ static char st2[32768];
|
||||
puts ("start f1a");
|
||||
if (getcontext (&ctx[2]) != 0)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ f1a (void)
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
- char st1[32768];
|
||||
+ static char st1[32768];
|
||||
puts ("making contexts");
|
||||
if (getcontext (&ctx[0]) != 0)
|
||||
{
|
@ -0,0 +1,100 @@
|
||||
commit a55e109709af55e6ed67d3f9536cac5d929c982e
|
||||
Author: Carlos O'Donell <carlos@redhat.com>
|
||||
Date: Wed Sep 5 01:16:42 2018 -0400
|
||||
|
||||
Fix tst-setcontext9 for optimized small stacks.
|
||||
|
||||
If the compiler reduces the stack usage in function f1 before calling
|
||||
into function f2, then when we swapcontext back to f1 and continue
|
||||
execution we may overwrite registers that were spilled to the stack
|
||||
while f2 was executing. Later when we return to f2 the corrupt
|
||||
registers will be reloaded from the stack and the test will crash. This
|
||||
was most commonly observed on i686 with __x86.get_pc_thunk.dx and
|
||||
needing to save and restore $edx. Overall i686 has few registers and
|
||||
the spilling to the stack is bound to happen, therefore the solution to
|
||||
making this test robust is to split function f1 into two parts f1a and
|
||||
f1b, and allocate f1b it's own stack such that subsequent execution does
|
||||
not overwrite the stack in use by function f2.
|
||||
|
||||
Tested on i686 and x86_64.
|
||||
|
||||
Signed-off-by: Carlos O'Donell <carlos@redhat.com>
|
||||
(cherry picked from commit 791b350dc725545e3f9b5db0f97ebdbc60c9735f)
|
||||
|
||||
diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c
|
||||
index 4636ce9030fa38a7..db8355766ca7b906 100644
|
||||
--- a/stdlib/tst-setcontext9.c
|
||||
+++ b/stdlib/tst-setcontext9.c
|
||||
@@ -41,26 +41,55 @@ f2 (void)
|
||||
}
|
||||
|
||||
static void
|
||||
-f1 (void)
|
||||
+f1b (void)
|
||||
{
|
||||
- puts ("start f1");
|
||||
- if (getcontext (&ctx[2]) != 0)
|
||||
- {
|
||||
- printf ("%s: getcontext: %m\n", __FUNCTION__);
|
||||
- exit (EXIT_FAILURE);
|
||||
- }
|
||||
if (done)
|
||||
{
|
||||
- puts ("set context in f1");
|
||||
+ puts ("set context in f1b");
|
||||
if (setcontext (&ctx[3]) != 0)
|
||||
{
|
||||
printf ("%s: setcontext: %m\n", __FUNCTION__);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
+ exit (EXIT_FAILURE);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+f1a (void)
|
||||
+{
|
||||
+ char st2[32768];
|
||||
+ puts ("start f1a");
|
||||
+ if (getcontext (&ctx[2]) != 0)
|
||||
+ {
|
||||
+ printf ("%s: getcontext: %m\n", __FUNCTION__);
|
||||
+ exit (EXIT_FAILURE);
|
||||
+ }
|
||||
+ ctx[2].uc_stack.ss_sp = st2;
|
||||
+ ctx[2].uc_stack.ss_size = sizeof st2;
|
||||
+ ctx[2].uc_link = &ctx[0];
|
||||
+ makecontext (&ctx[2], (void (*) (void)) f1b, 0);
|
||||
f2 ();
|
||||
}
|
||||
|
||||
+/* The execution path through the test looks like this:
|
||||
+ do_test (call)
|
||||
+ -> "making contexts"
|
||||
+ -> "swap contexts"
|
||||
+ f1a (via swapcontext to ctx[1], with alternate stack)
|
||||
+ -> "start f1a"
|
||||
+ f2 (call)
|
||||
+ -> "swap contexts in f2"
|
||||
+ f1b (via swapcontext to ctx[2], with alternate stack)
|
||||
+ -> "set context in f1b"
|
||||
+ do_test (via setcontext to ctx[3], main stack)
|
||||
+ -> "setcontext"
|
||||
+ f2 (via setcontext to ctx[4], with alternate stack)
|
||||
+ -> "end f2"
|
||||
+
|
||||
+ We must use an alternate stack for f1b, because if we don't then the
|
||||
+ result of executing an earlier caller may overwrite registers
|
||||
+ spilled to the stack in f2. */
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
@@ -79,7 +108,7 @@ do_test (void)
|
||||
ctx[1].uc_stack.ss_sp = st1;
|
||||
ctx[1].uc_stack.ss_size = sizeof st1;
|
||||
ctx[1].uc_link = &ctx[0];
|
||||
- makecontext (&ctx[1], (void (*) (void)) f1, 0);
|
||||
+ makecontext (&ctx[1], (void (*) (void)) f1a, 0);
|
||||
puts ("swap contexts");
|
||||
if (swapcontext (&ctx[3], &ctx[1]) != 0)
|
||||
{
|
@ -0,0 +1,61 @@
|
||||
commit b297581acb66f80b513996c1580158b0fb12d469
|
||||
Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
||||
Date: Mon Jan 14 17:54:44 2019 -0200
|
||||
|
||||
Add XFAIL_ROUNDING_IBM128_LIBGCC to more fma() tests
|
||||
|
||||
Ignore 16 errors in math/test-ldouble-fma and 4 errors in
|
||||
math/test-ildouble-fma when IBM 128-bit long double used.
|
||||
These errors are caused by spurious overflows from libgcc.
|
||||
|
||||
* math/libm-test-fma.inc (fma_test_data): Set
|
||||
XFAIL_ROUNDING_IBM128_LIBGCC to more tests.
|
||||
|
||||
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
||||
(cherry picked from commit ecdacd34a2ac3b6d5a529ff218b29261d9d98a7a)
|
||||
|
||||
diff --git a/math/libm-test-fma.inc b/math/libm-test-fma.inc
|
||||
index 5b29fb820194e055..a7ee40992420c1ab 100644
|
||||
--- a/math/libm-test-fma.inc
|
||||
+++ b/math/libm-test-fma.inc
|
||||
@@ -119,32 +119,32 @@ static const struct test_fff_f_data fma_test_data[] =
|
||||
TEST_fff_f (fma, plus_infty, plus_infty, -min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, plus_infty, min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, plus_infty, -min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, plus_infty, plus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, plus_infty, plus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
+ TEST_fff_f (fma, plus_infty, plus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
+ TEST_fff_f (fma, plus_infty, plus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
TEST_fff_f (fma, plus_infty, minus_infty, plus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, minus_infty, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, minus_infty, min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, minus_infty, -min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, minus_infty, min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, plus_infty, minus_infty, -min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, plus_infty, minus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, plus_infty, minus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
+ TEST_fff_f (fma, plus_infty, minus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
+ TEST_fff_f (fma, plus_infty, minus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
TEST_fff_f (fma, minus_infty, plus_infty, plus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, plus_infty, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, plus_infty, min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, plus_infty, -min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, plus_infty, min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, plus_infty, -min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, minus_infty, plus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, minus_infty, plus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
+ TEST_fff_f (fma, minus_infty, plus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
+ TEST_fff_f (fma, minus_infty, plus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
TEST_fff_f (fma, minus_infty, minus_infty, plus_zero, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, minus_infty, minus_zero, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, minus_infty, min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, minus_infty, -min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, minus_infty, min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
TEST_fff_f (fma, minus_infty, minus_infty, -min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, minus_infty, minus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
- TEST_fff_f (fma, minus_infty, minus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
|
||||
+ TEST_fff_f (fma, minus_infty, minus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
+ TEST_fff_f (fma, minus_infty, minus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC),
|
||||
|
||||
AUTO_TESTS_fff_f (fma),
|
||||
};
|
@ -0,0 +1,29 @@
|
||||
commit e7d22db29cfdd2f1fb97a70a76fa53d151569945
|
||||
Author: Mingli Yu <Mingli.Yu@windriver.com>
|
||||
Date: Thu Sep 20 12:41:13 2018 +0200
|
||||
|
||||
Linux gethostid: Check for NULL value from gethostbyname_r [BZ #23679]
|
||||
|
||||
A NULL value can happen with certain gethostbyname_r failures.
|
||||
|
||||
(cherry picked from commit 1214ba06e6771acb953a190091b0f6055c64fd25)
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c
|
||||
index 2e20f034dc134cc7..ee0190e7f945db1f 100644
|
||||
--- a/sysdeps/unix/sysv/linux/gethostid.c
|
||||
+++ b/sysdeps/unix/sysv/linux/gethostid.c
|
||||
@@ -102,12 +102,12 @@ gethostid (void)
|
||||
{
|
||||
int ret = __gethostbyname_r (hostname, &hostbuf,
|
||||
tmpbuf.data, tmpbuf.length, &hp, &herr);
|
||||
- if (ret == 0)
|
||||
+ if (ret == 0 && hp != NULL)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Enlarge the buffer on ERANGE. */
|
||||
- if (herr == NETDB_INTERNAL && errno == ERANGE)
|
||||
+ if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (&tmpbuf))
|
||||
return 0;
|
@ -0,0 +1,146 @@
|
||||
commit 307d04334d516bb180f484a2b283f97310bfee66
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Sep 20 12:03:01 2018 +0200
|
||||
|
||||
misc: New test misc/tst-gethostid
|
||||
|
||||
The empty /etc/hosts file used to trigger bug 23679.
|
||||
|
||||
(cherry picked from commit db9a8ad4ff3fc58e3773a9a4d0cabe3c1bc9c94c)
|
||||
|
||||
diff --git a/misc/Makefile b/misc/Makefile
|
||||
index b7be2bc19a6f7ed5..c9f81515ac9aef2c 100644
|
||||
--- a/misc/Makefile
|
||||
+++ b/misc/Makefile
|
||||
@@ -86,6 +86,11 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
|
||||
tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
|
||||
tst-preadvwritev2 tst-preadvwritev64v2
|
||||
|
||||
+# Tests which need libdl.
|
||||
+ifeq (yes,$(build-shared))
|
||||
+tests += tst-gethostid
|
||||
+endif
|
||||
+
|
||||
tests-internal := tst-atomic tst-atomic-long tst-allocate_once
|
||||
tests-static := tst-empty
|
||||
|
||||
@@ -145,3 +150,5 @@ tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace
|
||||
$(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
+
|
||||
+$(objpfx)tst-gethostid: $(libdl)
|
||||
diff --git a/misc/tst-gethostid.c b/misc/tst-gethostid.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..1490aaf3f517ff1d
|
||||
--- /dev/null
|
||||
+++ b/misc/tst-gethostid.c
|
||||
@@ -0,0 +1,108 @@
|
||||
+/* Basic test for gethostid.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <nss.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Initial test is run outside a chroot, to increase the likelihood of
|
||||
+ success. */
|
||||
+static void
|
||||
+outside_chroot (void *closure)
|
||||
+{
|
||||
+ long id = gethostid ();
|
||||
+ printf ("info: host ID outside chroot: 0x%lx\n", id);
|
||||
+}
|
||||
+
|
||||
+/* The same, but this time perform a chroot operation. */
|
||||
+static void
|
||||
+in_chroot (void *closure)
|
||||
+{
|
||||
+ const char *chroot_path = closure;
|
||||
+ xchroot (chroot_path);
|
||||
+ long id = gethostid ();
|
||||
+ printf ("info: host ID in chroot: 0x%lx\n", id);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ support_isolate_in_subprocess (outside_chroot, NULL);
|
||||
+
|
||||
+ /* Now run the test inside a chroot. */
|
||||
+ support_become_root ();
|
||||
+ if (!support_can_chroot ())
|
||||
+ /* Cannot perform further tests. */
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Only use nss_files. */
|
||||
+ __nss_configure_lookup ("hosts", "files");
|
||||
+
|
||||
+ /* Load the DSO outside of the chroot. */
|
||||
+ xdlopen (LIBNSS_FILES_SO, RTLD_LAZY);
|
||||
+
|
||||
+ char *chroot_dir = support_create_temp_directory ("tst-gethostid-");
|
||||
+ support_isolate_in_subprocess (in_chroot, chroot_dir);
|
||||
+
|
||||
+ /* Tests with /etc/hosts in the chroot. */
|
||||
+ {
|
||||
+ char *path = xasprintf ("%s/etc", chroot_dir);
|
||||
+ add_temp_file (path);
|
||||
+ xmkdir (path, 0777);
|
||||
+ free (path);
|
||||
+ path = xasprintf ("%s/etc/hosts", chroot_dir);
|
||||
+ add_temp_file (path);
|
||||
+
|
||||
+ FILE *fp = xfopen (path, "w");
|
||||
+ xfclose (fp);
|
||||
+ printf ("info: chroot test with an empty /etc/hosts file\n");
|
||||
+ support_isolate_in_subprocess (in_chroot, chroot_dir);
|
||||
+
|
||||
+ char hostname[1024];
|
||||
+ int ret = gethostname (hostname, sizeof (hostname));
|
||||
+ if (ret < 0)
|
||||
+ printf ("warning: invalid result from gethostname: %d\n", ret);
|
||||
+ else if (strlen (hostname) == 0)
|
||||
+ puts ("warning: gethostname returned empty string");
|
||||
+ else
|
||||
+ {
|
||||
+ printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n",
|
||||
+ hostname);
|
||||
+ fp = xfopen (path, "w");
|
||||
+ /* Use an IPv6 address to induce another lookup failure. */
|
||||
+ fprintf (fp, "2001:db8::1 %s\n", hostname);
|
||||
+ xfclose (fp);
|
||||
+ support_isolate_in_subprocess (in_chroot, chroot_dir);
|
||||
+ }
|
||||
+ free (path);
|
||||
+ }
|
||||
+ free (chroot_dir);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,108 @@
|
||||
commit 0ef2f4400c06927af34c515555f68840a70ba409
|
||||
Author: Wilco Dijkstra <wdijkstr@arm.com>
|
||||
Date: Wed Sep 19 16:50:18 2018 +0100
|
||||
|
||||
Fix strstr bug with huge needles (bug 23637)
|
||||
|
||||
The generic strstr in GLIBC 2.28 fails to match huge needles. The optimized
|
||||
AVAILABLE macro reads ahead a large fixed amount to reduce the overhead of
|
||||
repeatedly checking for the end of the string. However if the needle length
|
||||
is larger than this, two_way_long_needle may confuse this as meaning the end
|
||||
of the string and return NULL. This is fixed by adding the needle length to
|
||||
the amount to read ahead.
|
||||
|
||||
[BZ #23637]
|
||||
* string/test-strstr.c (pr23637): New function.
|
||||
(test_main): Add tests with longer needles.
|
||||
* string/strcasestr.c (AVAILABLE): Fix readahead distance.
|
||||
* string/strstr.c (AVAILABLE): Likewise.
|
||||
|
||||
(cherry picked from commit 83a552b0bb9fc2a5e80a0ab3723c0a80ce1db9f2)
|
||||
|
||||
diff --git a/string/strcasestr.c b/string/strcasestr.c
|
||||
index 5909fe3cdba88e47..421764bd1b0ff22e 100644
|
||||
--- a/string/strcasestr.c
|
||||
+++ b/string/strcasestr.c
|
||||
@@ -37,8 +37,9 @@
|
||||
/* Two-Way algorithm. */
|
||||
#define RETURN_TYPE char *
|
||||
#define AVAILABLE(h, h_l, j, n_l) \
|
||||
- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
|
||||
- (j) + (n_l) <= (h_l)))
|
||||
+ (((j) + (n_l) <= (h_l)) \
|
||||
+ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
|
||||
+ (j) + (n_l) <= (h_l)))
|
||||
#define CHECK_EOL (1)
|
||||
#define RET0_IF_0(a) if (!a) goto ret0
|
||||
#define CANON_ELEMENT(c) TOLOWER (c)
|
||||
diff --git a/string/strstr.c b/string/strstr.c
|
||||
index 265e9f310ce507ce..79ebcc75329d0b17 100644
|
||||
--- a/string/strstr.c
|
||||
+++ b/string/strstr.c
|
||||
@@ -33,8 +33,9 @@
|
||||
|
||||
#define RETURN_TYPE char *
|
||||
#define AVAILABLE(h, h_l, j, n_l) \
|
||||
- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
|
||||
- (j) + (n_l) <= (h_l)))
|
||||
+ (((j) + (n_l) <= (h_l)) \
|
||||
+ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
|
||||
+ (j) + (n_l) <= (h_l)))
|
||||
#define CHECK_EOL (1)
|
||||
#define RET0_IF_0(a) if (!a) goto ret0
|
||||
#define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
|
||||
diff --git a/string/test-strstr.c b/string/test-strstr.c
|
||||
index 8d99716ff39cc2c2..5861b01b73e4c315 100644
|
||||
--- a/string/test-strstr.c
|
||||
+++ b/string/test-strstr.c
|
||||
@@ -151,6 +151,32 @@ check2 (void)
|
||||
}
|
||||
}
|
||||
|
||||
+#define N 1024
|
||||
+
|
||||
+static void
|
||||
+pr23637 (void)
|
||||
+{
|
||||
+ char *h = (char*) buf1;
|
||||
+ char *n = (char*) buf2;
|
||||
+
|
||||
+ for (int i = 0; i < N; i++)
|
||||
+ {
|
||||
+ n[i] = 'x';
|
||||
+ h[i] = ' ';
|
||||
+ h[i + N] = 'x';
|
||||
+ }
|
||||
+
|
||||
+ n[N] = '\0';
|
||||
+ h[N * 2] = '\0';
|
||||
+
|
||||
+ /* Ensure we don't match at the first 'x'. */
|
||||
+ h[0] = 'x';
|
||||
+
|
||||
+ char *exp_result = stupid_strstr (h, n);
|
||||
+ FOR_EACH_IMPL (impl, 0)
|
||||
+ check_result (impl, h, n, exp_result);
|
||||
+}
|
||||
+
|
||||
static int
|
||||
test_main (void)
|
||||
{
|
||||
@@ -158,6 +184,7 @@ test_main (void)
|
||||
|
||||
check1 ();
|
||||
check2 ();
|
||||
+ pr23637 ();
|
||||
|
||||
printf ("%23s", "");
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
@@ -202,6 +229,9 @@ test_main (void)
|
||||
do_test (15, 9, hlen, klen, 1);
|
||||
do_test (15, 15, hlen, klen, 0);
|
||||
do_test (15, 15, hlen, klen, 1);
|
||||
+
|
||||
+ do_test (15, 15, hlen + klen * 4, klen * 4, 0);
|
||||
+ do_test (15, 15, hlen + klen * 4, klen * 4, 1);
|
||||
}
|
||||
|
||||
do_test (0, 0, page_size - 1, 16, 0);
|
@ -0,0 +1,82 @@
|
||||
commit 2339d6a55eb7a7e040ae888e906adc49eeb59eab
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Wed Sep 12 08:40:59 2018 -0700
|
||||
|
||||
i386: Use ENTRY and END in start.S [BZ #23606]
|
||||
|
||||
Wrapping the _start function with ENTRY and END to insert ENDBR32 at
|
||||
function entry when CET is enabled. Since _start now includes CFI,
|
||||
without "cfi_undefined (eip)", unwinder may not terminate at _start
|
||||
and we will get
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0xf7dc661e in ?? () from /lib/libgcc_s.so.1
|
||||
Missing separate debuginfos, use: dnf debuginfo-install libgcc-8.2.1-3.0.fc28.i686
|
||||
(gdb) bt
|
||||
#0 0xf7dc661e in ?? () from /lib/libgcc_s.so.1
|
||||
#1 0xf7dc7c18 in _Unwind_Backtrace () from /lib/libgcc_s.so.1
|
||||
#2 0xf7f0d809 in __GI___backtrace (array=array@entry=0xffffc7d0,
|
||||
size=size@entry=20) at ../sysdeps/i386/backtrace.c:127
|
||||
#3 0x08049254 in compare (p1=p1@entry=0xffffcad0, p2=p2@entry=0xffffcad4)
|
||||
at backtrace-tst.c:12
|
||||
#4 0xf7e2a28c in msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0,
|
||||
n=n@entry=2) at msort.c:65
|
||||
#5 0xf7e29f64 in msort_with_tmp (n=2, b=0xffffcad0, p=0xffffca5c)
|
||||
at msort.c:53
|
||||
#6 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=5)
|
||||
at msort.c:53
|
||||
#7 0xf7e29f64 in msort_with_tmp (n=5, b=0xffffcad0, p=0xffffca5c)
|
||||
at msort.c:53
|
||||
#8 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=10)
|
||||
at msort.c:53
|
||||
#9 0xf7e29f64 in msort_with_tmp (n=10, b=0xffffcad0, p=0xffffca5c)
|
||||
at msort.c:53
|
||||
#10 msort_with_tmp (p=p@entry=0xffffca5c, b=b@entry=0xffffcad0, n=n@entry=20)
|
||||
at msort.c:53
|
||||
#11 0xf7e2a5b6 in msort_with_tmp (n=20, b=0xffffcad0, p=0xffffca5c)
|
||||
at msort.c:297
|
||||
#12 __GI___qsort_r (b=b@entry=0xffffcad0, n=n@entry=20, s=s@entry=4,
|
||||
cmp=cmp@entry=0x8049230 <compare>, arg=arg@entry=0x0) at msort.c:297
|
||||
#13 0xf7e2a84d in __GI_qsort (b=b@entry=0xffffcad0, n=n@entry=20, s=s@entry=4,
|
||||
cmp=cmp@entry=0x8049230 <compare>) at msort.c:308
|
||||
#14 0x080490f6 in main (argc=2, argv=0xffffcbd4) at backtrace-tst.c:39
|
||||
|
||||
FAIL: debug/backtrace-tst
|
||||
|
||||
[BZ #23606]
|
||||
* sysdeps/i386/start.S: Include <sysdep.h>
|
||||
(_start): Use ENTRY/END to insert ENDBR32 at entry when CET is
|
||||
enabled. Add cfi_undefined (eip).
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
|
||||
(cherry picked from commit 5a274db4ea363d6b0b92933f085a92daaf1be2f2)
|
||||
|
||||
diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S
|
||||
index 91035fa83fb7ee38..e35e9bd31b2cea30 100644
|
||||
--- a/sysdeps/i386/start.S
|
||||
+++ b/sysdeps/i386/start.S
|
||||
@@ -52,10 +52,11 @@
|
||||
NULL
|
||||
*/
|
||||
|
||||
- .text
|
||||
- .globl _start
|
||||
- .type _start,@function
|
||||
-_start:
|
||||
+#include <sysdep.h>
|
||||
+
|
||||
+ENTRY (_start)
|
||||
+ /* Clearing frame pointer is insufficient, use CFI. */
|
||||
+ cfi_undefined (eip)
|
||||
/* Clear the frame pointer. The ABI suggests this be done, to mark
|
||||
the outermost frame obviously. */
|
||||
xorl %ebp, %ebp
|
||||
@@ -131,6 +132,7 @@ _start:
|
||||
1: movl (%esp), %ebx
|
||||
ret
|
||||
#endif
|
||||
+END (_start)
|
||||
|
||||
/* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so
|
||||
meaningless since we don't support machines < 80386. */
|
@ -0,0 +1,483 @@
|
||||
commit e5d262effe3a87164308a3f37e61b32d0348692a
|
||||
Author: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
||||
Date: Fri Nov 30 18:05:32 2018 -0200
|
||||
|
||||
Fix _dl_profile_fixup data-dependency issue (Bug 23690)
|
||||
|
||||
There is a data-dependency between the fields of struct l_reloc_result
|
||||
and the field used as the initialization guard. Users of the guard
|
||||
expect writes to the structure to be observable when they also observe
|
||||
the guard initialized. The solution for this problem is to use an acquire
|
||||
and release load and store to ensure previous writes to the structure are
|
||||
observable if the guard is initialized.
|
||||
|
||||
The previous implementation used DL_FIXUP_VALUE_ADDR (l_reloc_result->addr)
|
||||
as the initialization guard, making it impossible for some architectures
|
||||
to load and store it atomically, i.e. hppa and ia64, due to its larger size.
|
||||
|
||||
This commit adds an unsigned int to l_reloc_result to be used as the new
|
||||
initialization guard of the struct, making it possible to load and store
|
||||
it atomically in all architectures. The fix ensures that the values
|
||||
observed in l_reloc_result are consistent and do not lead to crashes.
|
||||
The algorithm is documented in the code in elf/dl-runtime.c
|
||||
(_dl_profile_fixup). Not all data races have been eliminated.
|
||||
|
||||
Tested with build-many-glibcs and on powerpc, powerpc64, and powerpc64le.
|
||||
|
||||
[BZ #23690]
|
||||
* elf/dl-runtime.c (_dl_profile_fixup): Guarantee memory
|
||||
modification order when accessing reloc_result->addr.
|
||||
* include/link.h (reloc_result): Add field init.
|
||||
* nptl/Makefile (tests): Add tst-audit-threads.
|
||||
(modules-names): Add tst-audit-threads-mod1 and
|
||||
tst-audit-threads-mod2.
|
||||
Add rules to build tst-audit-threads.
|
||||
* nptl/tst-audit-threads-mod1.c: New file.
|
||||
* nptl/tst-audit-threads-mod2.c: Likewise.
|
||||
* nptl/tst-audit-threads.c: Likewise.
|
||||
* nptl/tst-audit-threads.h: Likewise.
|
||||
|
||||
Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
|
||||
index 63bbc89776..3d2f4a7a76 100644
|
||||
--- a/elf/dl-runtime.c
|
||||
+++ b/elf/dl-runtime.c
|
||||
@@ -183,10 +183,36 @@ _dl_profile_fixup (
|
||||
/* This is the address in the array where we store the result of previous
|
||||
relocations. */
|
||||
struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index];
|
||||
- DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr;
|
||||
|
||||
- DL_FIXUP_VALUE_TYPE value = *resultp;
|
||||
- if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0)
|
||||
+ /* CONCURRENCY NOTES:
|
||||
+
|
||||
+ Multiple threads may be calling the same PLT sequence and with
|
||||
+ LD_AUDIT enabled they will be calling into _dl_profile_fixup to
|
||||
+ update the reloc_result with the result of the lazy resolution.
|
||||
+ The reloc_result guard variable is reloc_init, and we use
|
||||
+ acquire/release loads and store to it to ensure that the results of
|
||||
+ the structure are consistent with the loaded value of the guard.
|
||||
+ This does not fix all of the data races that occur when two or more
|
||||
+ threads read reloc_result->reloc_init with a value of zero and read
|
||||
+ and write to that reloc_result concurrently. The expectation is
|
||||
+ generally that while this is a data race it works because the
|
||||
+ threads write the same values. Until the data races are fixed
|
||||
+ there is a potential for problems to arise from these data races.
|
||||
+ The reloc result updates should happen in parallel but there should
|
||||
+ be an atomic RMW which does the final update to the real result
|
||||
+ entry (see bug 23790).
|
||||
+
|
||||
+ The following code uses reloc_result->init set to 0 to indicate if it is
|
||||
+ the first time this object is being relocated, otherwise 1 which
|
||||
+ indicates the object has already been relocated.
|
||||
+
|
||||
+ Reading/Writing from/to reloc_result->reloc_init must not happen
|
||||
+ before previous writes to reloc_result complete as they could
|
||||
+ end-up with an incomplete struct. */
|
||||
+ DL_FIXUP_VALUE_TYPE value;
|
||||
+ unsigned int init = atomic_load_acquire (&reloc_result->init);
|
||||
+
|
||||
+ if (init == 0)
|
||||
{
|
||||
/* This is the first time we have to relocate this object. */
|
||||
const ElfW(Sym) *const symtab
|
||||
@@ -346,19 +372,31 @@ _dl_profile_fixup (
|
||||
|
||||
/* Store the result for later runs. */
|
||||
if (__glibc_likely (! GLRO(dl_bind_not)))
|
||||
- *resultp = value;
|
||||
+ {
|
||||
+ reloc_result->addr = value;
|
||||
+ /* Guarantee all previous writes complete before
|
||||
+ init is updated. See CONCURRENCY NOTES earlier */
|
||||
+ atomic_store_release (&reloc_result->init, 1);
|
||||
+ }
|
||||
+ init = 1;
|
||||
}
|
||||
+ else
|
||||
+ value = reloc_result->addr;
|
||||
|
||||
/* By default we do not call the pltexit function. */
|
||||
long int framesize = -1;
|
||||
|
||||
+
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: report the PLT entering and allow the
|
||||
auditors to change the value. */
|
||||
- if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0
|
||||
+ if (GLRO(dl_naudit) > 0
|
||||
/* Don't do anything if no auditor wants to intercept this call. */
|
||||
&& (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
|
||||
{
|
||||
+ /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been
|
||||
+ initialized earlier in this function or in another thread. */
|
||||
+ assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0);
|
||||
ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
|
||||
l_info[DT_SYMTAB])
|
||||
+ reloc_result->boundndx);
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index 5924594548..83b1c34b7b 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -216,6 +216,10 @@ struct link_map
|
||||
unsigned int boundndx;
|
||||
uint32_t enterexit;
|
||||
unsigned int flags;
|
||||
+ /* CONCURRENCY NOTE: This is used to guard the concurrent initialization
|
||||
+ of the relocation result across multiple threads. See the more
|
||||
+ detailed notes in elf/dl-runtime.c. */
|
||||
+ unsigned int init;
|
||||
} *l_reloc_result;
|
||||
|
||||
/* Pointer to the version information if available. */
|
||||
diff --git a/nptl/Makefile b/nptl/Makefile
|
||||
index 982e43adfa..98b0aa01c7 100644
|
||||
--- a/nptl/Makefile
|
||||
+++ b/nptl/Makefile
|
||||
@@ -382,7 +382,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
|
||||
tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \
|
||||
tst-oncex3 tst-oncex4
|
||||
ifeq ($(build-shared),yes)
|
||||
-tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder
|
||||
+tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \
|
||||
+ tst-audit-threads
|
||||
tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1
|
||||
tests-nolibpthread += tst-fini1
|
||||
ifeq ($(have-z-execstack),yes)
|
||||
@@ -394,7 +395,8 @@ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
|
||||
tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
|
||||
tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
|
||||
tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \
|
||||
- tst-join7mod tst-compat-forwarder-mod
|
||||
+ tst-join7mod tst-compat-forwarder-mod tst-audit-threads-mod1 \
|
||||
+ tst-audit-threads-mod2
|
||||
extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \
|
||||
tst-cleanup4aux.o tst-cleanupx4aux.o
|
||||
test-extras += tst-cleanup4aux tst-cleanupx4aux
|
||||
@@ -712,6 +714,14 @@ $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so
|
||||
|
||||
tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1
|
||||
|
||||
+# Protect against a build using -Wl,-z,now.
|
||||
+LDFLAGS-tst-audit-threads-mod1.so = -Wl,-z,lazy
|
||||
+LDFLAGS-tst-audit-threads-mod2.so = -Wl,-z,lazy
|
||||
+LDFLAGS-tst-audit-threads = -Wl,-z,lazy
|
||||
+$(objpfx)tst-audit-threads: $(objpfx)tst-audit-threads-mod2.so
|
||||
+$(objpfx)tst-audit-threads.out: $(objpfx)tst-audit-threads-mod1.so
|
||||
+tst-audit-threads-ENV = LD_AUDIT=$(objpfx)tst-audit-threads-mod1.so
|
||||
+
|
||||
# The tests here better do not run in parallel
|
||||
ifneq ($(filter %tests,$(MAKECMDGOALS)),)
|
||||
.NOTPARALLEL:
|
||||
diff --git a/nptl/tst-audit-threads-mod1.c b/nptl/tst-audit-threads-mod1.c
|
||||
new file mode 100644
|
||||
index 0000000000..615d5ee512
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-audit-threads-mod1.c
|
||||
@@ -0,0 +1,74 @@
|
||||
+/* Dummy audit library for test-audit-threads.
|
||||
+
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <elf.h>
|
||||
+#include <link.h>
|
||||
+#include <stdio.h>
|
||||
+#include <assert.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+/* We must use a dummy LD_AUDIT module to force the dynamic loader to
|
||||
+ *not* update the real PLT, and instead use a cached value for the
|
||||
+ lazy resolution result. It is the update of that cached value that
|
||||
+ we are testing for correctness by doing this. */
|
||||
+
|
||||
+/* Library to be audited. */
|
||||
+#define LIB "tst-audit-threads-mod2.so"
|
||||
+/* CALLNUM is the number of retNum functions. */
|
||||
+#define CALLNUM 7999
|
||||
+
|
||||
+#define CONCATX(a, b) __CONCAT (a, b)
|
||||
+
|
||||
+static int previous = 0;
|
||||
+
|
||||
+unsigned int
|
||||
+la_version (unsigned int ver)
|
||||
+{
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+unsigned int
|
||||
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
|
||||
+{
|
||||
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
|
||||
+}
|
||||
+
|
||||
+uintptr_t
|
||||
+CONCATX(la_symbind, __ELF_NATIVE_CLASS) (ElfW(Sym) *sym,
|
||||
+ unsigned int ndx,
|
||||
+ uintptr_t *refcook,
|
||||
+ uintptr_t *defcook,
|
||||
+ unsigned int *flags,
|
||||
+ const char *symname)
|
||||
+{
|
||||
+ const char * retnum = "retNum";
|
||||
+ char * num = strstr (symname, retnum);
|
||||
+ int n;
|
||||
+ /* Validate if the symbols are getting called in the correct order.
|
||||
+ This code is here to verify binutils does not optimize out the PLT
|
||||
+ entries that require the symbol binding. */
|
||||
+ if (num != NULL)
|
||||
+ {
|
||||
+ n = atoi (num);
|
||||
+ assert (n >= previous);
|
||||
+ assert (n <= CALLNUM);
|
||||
+ previous = n;
|
||||
+ }
|
||||
+ return sym->st_value;
|
||||
+}
|
||||
diff --git a/nptl/tst-audit-threads-mod2.c b/nptl/tst-audit-threads-mod2.c
|
||||
new file mode 100644
|
||||
index 0000000000..f9817dd3dc
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-audit-threads-mod2.c
|
||||
@@ -0,0 +1,22 @@
|
||||
+/* Shared object with a huge number of functions for test-audit-threads.
|
||||
+
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* Define all the retNumN functions in a library. */
|
||||
+#define definenum
|
||||
+#include "tst-audit-threads.h"
|
||||
diff --git a/nptl/tst-audit-threads.c b/nptl/tst-audit-threads.c
|
||||
new file mode 100644
|
||||
index 0000000000..e4bf433bd8
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-audit-threads.c
|
||||
@@ -0,0 +1,97 @@
|
||||
+/* Test multi-threading using LD_AUDIT.
|
||||
+
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* This test uses a dummy LD_AUDIT library (test-audit-threads-mod1) and a
|
||||
+ library with a huge number of functions in order to validate lazy symbol
|
||||
+ binding with an audit library. We use one thread per CPU to test that
|
||||
+ concurrent lazy resolution does not have any defects which would cause
|
||||
+ the process to fail. We use an LD_AUDIT library to force the testing of
|
||||
+ the relocation resolution caching code in the dynamic loader i.e.
|
||||
+ _dl_runtime_profile and _dl_profile_fixup. */
|
||||
+
|
||||
+#include <support/xthread.h>
|
||||
+#include <strings.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <sys/sysinfo.h>
|
||||
+
|
||||
+static int do_test (void);
|
||||
+
|
||||
+/* This test usually takes less than 3s to run. However, there are cases that
|
||||
+ take up to 30s. */
|
||||
+#define TIMEOUT 60
|
||||
+#define TEST_FUNCTION do_test ()
|
||||
+#include "../test-skeleton.c"
|
||||
+
|
||||
+/* Declare the functions we are going to call. */
|
||||
+#define externnum
|
||||
+#include "tst-audit-threads.h"
|
||||
+#undef externnum
|
||||
+
|
||||
+int num_threads;
|
||||
+pthread_barrier_t barrier;
|
||||
+
|
||||
+void
|
||||
+sync_all (int num)
|
||||
+{
|
||||
+ pthread_barrier_wait (&barrier);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+call_all_ret_nums (void)
|
||||
+{
|
||||
+ /* Call each function one at a time from all threads. */
|
||||
+#define callnum
|
||||
+#include "tst-audit-threads.h"
|
||||
+#undef callnum
|
||||
+}
|
||||
+
|
||||
+void *
|
||||
+thread_main (void *unused)
|
||||
+{
|
||||
+ call_all_ret_nums ();
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+#define STR2(X) #X
|
||||
+#define STR(X) STR2(X)
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ int i;
|
||||
+ pthread_t *threads;
|
||||
+
|
||||
+ num_threads = get_nprocs ();
|
||||
+ if (num_threads <= 1)
|
||||
+ num_threads = 2;
|
||||
+
|
||||
+ /* Used to synchronize all the threads after calling each retNumN. */
|
||||
+ xpthread_barrier_init (&barrier, NULL, num_threads);
|
||||
+
|
||||
+ threads = (pthread_t *) xcalloc (num_threads, sizeof(pthread_t));
|
||||
+ for (i = 0; i < num_threads; i++)
|
||||
+ threads[i] = xpthread_create(NULL, thread_main, NULL);
|
||||
+
|
||||
+ for (i = 0; i < num_threads; i++)
|
||||
+ xpthread_join(threads[i]);
|
||||
+
|
||||
+ free (threads);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
diff --git a/nptl/tst-audit-threads.h b/nptl/tst-audit-threads.h
|
||||
new file mode 100644
|
||||
index 0000000000..1c9ecc08df
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-audit-threads.h
|
||||
@@ -0,0 +1,92 @@
|
||||
+/* Helper header for test-audit-threads.
|
||||
+
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* We use this helper to create a large number of functions, all of
|
||||
+ which will be resolved lazily and thus have their PLT updated.
|
||||
+ This is done to provide enough functions that we can statistically
|
||||
+ observe a thread vs. PLT resolution failure if one exists. */
|
||||
+
|
||||
+#define CONCAT(a, b) a ## b
|
||||
+#define NUM(x, y) CONCAT (x, y)
|
||||
+
|
||||
+#define FUNC10(x) \
|
||||
+ FUNC (NUM (x, 0)); \
|
||||
+ FUNC (NUM (x, 1)); \
|
||||
+ FUNC (NUM (x, 2)); \
|
||||
+ FUNC (NUM (x, 3)); \
|
||||
+ FUNC (NUM (x, 4)); \
|
||||
+ FUNC (NUM (x, 5)); \
|
||||
+ FUNC (NUM (x, 6)); \
|
||||
+ FUNC (NUM (x, 7)); \
|
||||
+ FUNC (NUM (x, 8)); \
|
||||
+ FUNC (NUM (x, 9))
|
||||
+
|
||||
+#define FUNC100(x) \
|
||||
+ FUNC10 (NUM (x, 0)); \
|
||||
+ FUNC10 (NUM (x, 1)); \
|
||||
+ FUNC10 (NUM (x, 2)); \
|
||||
+ FUNC10 (NUM (x, 3)); \
|
||||
+ FUNC10 (NUM (x, 4)); \
|
||||
+ FUNC10 (NUM (x, 5)); \
|
||||
+ FUNC10 (NUM (x, 6)); \
|
||||
+ FUNC10 (NUM (x, 7)); \
|
||||
+ FUNC10 (NUM (x, 8)); \
|
||||
+ FUNC10 (NUM (x, 9))
|
||||
+
|
||||
+#define FUNC1000(x) \
|
||||
+ FUNC100 (NUM (x, 0)); \
|
||||
+ FUNC100 (NUM (x, 1)); \
|
||||
+ FUNC100 (NUM (x, 2)); \
|
||||
+ FUNC100 (NUM (x, 3)); \
|
||||
+ FUNC100 (NUM (x, 4)); \
|
||||
+ FUNC100 (NUM (x, 5)); \
|
||||
+ FUNC100 (NUM (x, 6)); \
|
||||
+ FUNC100 (NUM (x, 7)); \
|
||||
+ FUNC100 (NUM (x, 8)); \
|
||||
+ FUNC100 (NUM (x, 9))
|
||||
+
|
||||
+#define FUNC7000() \
|
||||
+ FUNC1000 (1); \
|
||||
+ FUNC1000 (2); \
|
||||
+ FUNC1000 (3); \
|
||||
+ FUNC1000 (4); \
|
||||
+ FUNC1000 (5); \
|
||||
+ FUNC1000 (6); \
|
||||
+ FUNC1000 (7);
|
||||
+
|
||||
+#ifdef FUNC
|
||||
+# undef FUNC
|
||||
+#endif
|
||||
+
|
||||
+#ifdef externnum
|
||||
+# define FUNC(x) extern int CONCAT (retNum, x) (void)
|
||||
+#endif
|
||||
+
|
||||
+#ifdef definenum
|
||||
+# define FUNC(x) int CONCAT (retNum, x) (void) { return x; }
|
||||
+#endif
|
||||
+
|
||||
+#ifdef callnum
|
||||
+# define FUNC(x) CONCAT (retNum, x) (); sync_all (x)
|
||||
+#endif
|
||||
+
|
||||
+/* A value of 7000 functions is chosen as an arbitrarily large
|
||||
+ number of functions that will allow us enough attempts to
|
||||
+ verify lazy resolution operation. */
|
||||
+FUNC7000 ();
|
@ -0,0 +1,35 @@
|
||||
commit ed643089cd3251038863d32e67ec47b94cd557f3
|
||||
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||
Date: Tue Oct 9 14:31:28 2018 +0100
|
||||
|
||||
Increase timeout of libio/tst-readline
|
||||
|
||||
Increase timeout from the default 20s to 100s. This test makes close to
|
||||
20 million syscalls with distribution:
|
||||
|
||||
12327675 read
|
||||
4143204 lseek
|
||||
929475 close
|
||||
929471 openat
|
||||
92817 fstat
|
||||
1431 write
|
||||
...
|
||||
|
||||
The default timeout assumes each can finish in 1us on average which
|
||||
is not true on slow machines.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
* libio/tst-readline.c (TIMEOUT): Define.
|
||||
|
||||
diff --git a/libio/tst-readline.c b/libio/tst-readline.c
|
||||
index 9322ef68da5e38a9..63f5227760d88c63 100644
|
||||
--- a/libio/tst-readline.c
|
||||
+++ b/libio/tst-readline.c
|
||||
@@ -232,5 +232,6 @@ do_test (void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#define TIMEOUT 100
|
||||
#define PREPARE prepare
|
||||
#include <support/test-driver.c>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,80 @@
|
||||
commit 6c3a8a9d868a8deddf0d6dcc785b6d120de90523
|
||||
Author: Paul Pluzhnikov <ppluzhnikov@kazbek.mtv.corp.google.com>
|
||||
Date: Fri Aug 24 18:08:51 2018 -0700
|
||||
|
||||
Fix BZ#23400 (creating temporary files in source tree), and undefined behavior in test.
|
||||
|
||||
diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c
|
||||
index e7837f98c19fc4bf..d1aa69106ccf6ac5 100644
|
||||
--- a/stdlib/test-bz22786.c
|
||||
+++ b/stdlib/test-bz22786.c
|
||||
@@ -26,28 +26,20 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <libc-diag.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
- const char dir[] = "bz22786";
|
||||
- const char lnk[] = "bz22786/symlink";
|
||||
+ const char *dir = support_create_temp_directory ("bz22786.");
|
||||
+ const char *lnk = xasprintf ("%s/symlink", dir);
|
||||
+ const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1;
|
||||
|
||||
- rmdir (dir);
|
||||
- if (mkdir (dir, 0755) != 0 && errno != EEXIST)
|
||||
- {
|
||||
- printf ("mkdir %s: %m\n", dir);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- if (symlink (".", lnk) != 0 && errno != EEXIST)
|
||||
- {
|
||||
- printf ("symlink (%s, %s): %m\n", dir, lnk);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- const size_t path_len = (size_t) INT_MAX + 1;
|
||||
+ TEST_VERIFY_EXIT (symlink (".", lnk) == 0);
|
||||
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
#if __GNUC_PREREQ (7, 0)
|
||||
@@ -55,20 +47,14 @@ do_test (void)
|
||||
allocation to succeed for the test to work. */
|
||||
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
|
||||
#endif
|
||||
- char *path = malloc (path_len);
|
||||
+ char *path = xmalloc (path_len);
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
|
||||
- if (path == NULL)
|
||||
- {
|
||||
- printf ("malloc (%zu): %m\n", path_len);
|
||||
- return EXIT_UNSUPPORTED;
|
||||
- }
|
||||
-
|
||||
- /* Construct very long path = "bz22786/symlink/aaaa....." */
|
||||
- char *p = mempcpy (path, lnk, sizeof (lnk) - 1);
|
||||
+ /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */
|
||||
+ char *p = mempcpy (path, lnk, strlen (lnk));
|
||||
*(p++) = '/';
|
||||
- memset (p, 'a', path_len - (path - p) - 2);
|
||||
- p[path_len - (path - p) - 1] = '\0';
|
||||
+ memset (p, 'a', path_len - (p - path) - 2);
|
||||
+ p[path_len - (p - path) - 1] = '\0';
|
||||
|
||||
/* This call crashes before the fix for bz22786 on 32-bit platforms. */
|
||||
p = realpath (path, NULL);
|
||||
@@ -81,7 +67,6 @@ do_test (void)
|
||||
|
||||
/* Cleanup. */
|
||||
unlink (lnk);
|
||||
- rmdir (dir);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
commit 3bad2358d67d371497079bba4f8eca9c0096f4e2
|
||||
Author: Stefan Liebler <stli@linux.ibm.com>
|
||||
Date: Thu Aug 30 08:44:32 2018 +0200
|
||||
|
||||
Test stdlib/test-bz22786 exits now with unsupported if malloc fails.
|
||||
|
||||
The test tries to allocate more than 2^31 bytes which will always fail on s390
|
||||
as it has maximum 2^31bit of memory.
|
||||
Before commit 6c3a8a9d868a8deddf0d6dcc785b6d120de90523, this test returned
|
||||
unsupported if malloc fails. This patch re enables this behaviour.
|
||||
|
||||
Furthermore support_delete_temp_files() failed to remove the temp directory
|
||||
in this case as it is not empty due to the created symlink.
|
||||
Thus the creation of the symlink is moved behind malloc.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
ChangeLog:
|
||||
|
||||
* stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED
|
||||
if malloc fails.
|
||||
|
||||
diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c
|
||||
index d1aa69106ccf6ac5..777bf9180f4b5022 100644
|
||||
--- a/stdlib/test-bz22786.c
|
||||
+++ b/stdlib/test-bz22786.c
|
||||
@@ -39,16 +39,25 @@ do_test (void)
|
||||
const char *lnk = xasprintf ("%s/symlink", dir);
|
||||
const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1;
|
||||
|
||||
- TEST_VERIFY_EXIT (symlink (".", lnk) == 0);
|
||||
-
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
#if __GNUC_PREREQ (7, 0)
|
||||
/* GCC 7 warns about too-large allocations; here we need such
|
||||
allocation to succeed for the test to work. */
|
||||
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
|
||||
#endif
|
||||
- char *path = xmalloc (path_len);
|
||||
+ char *path = malloc (path_len);
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
+ if (path == NULL)
|
||||
+ {
|
||||
+ printf ("malloc (%zu): %m\n", path_len);
|
||||
+ /* On 31-bit s390 the malloc will always fail as we do not have
|
||||
+ so much memory, and we want to mark the test unsupported.
|
||||
+ Likewise on systems with little physical memory the test will
|
||||
+ fail and should be unsupported. */
|
||||
+ return EXIT_UNSUPPORTED;
|
||||
+ }
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (symlink (".", lnk) == 0);
|
||||
|
||||
/* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */
|
||||
char *p = mempcpy (path, lnk, strlen (lnk));
|
@ -0,0 +1,65 @@
|
||||
commit f5e7e95921847bd83186bfe621fc2b48c4de5477
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Oct 30 13:11:47 2018 +0100
|
||||
|
||||
stdlib/test-bz22786: Avoid spurious test failures using alias mappings
|
||||
|
||||
On systems without enough random-access memory, stdlib/test-bz22786
|
||||
will go deeply into swap and time out, even with a substantial
|
||||
TIMEOUTFACTOR. This commit adds a facility to construct repeating
|
||||
strings with alias mappings, so that the requirement for physical
|
||||
memory, and uses it in stdlib/test-bz22786.
|
||||
|
||||
Adjusted here for conflicts due to the previous support/ backport in
|
||||
glibc-rh1638523-1.patch.
|
||||
|
||||
diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c
|
||||
index 777bf9180f4b5022..bb1e04f2debe9042 100644
|
||||
--- a/stdlib/test-bz22786.c
|
||||
+++ b/stdlib/test-bz22786.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
+#include <support/blob_repeat.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
@@ -39,17 +40,12 @@ do_test (void)
|
||||
const char *lnk = xasprintf ("%s/symlink", dir);
|
||||
const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1;
|
||||
|
||||
- DIAG_PUSH_NEEDS_COMMENT;
|
||||
-#if __GNUC_PREREQ (7, 0)
|
||||
- /* GCC 7 warns about too-large allocations; here we need such
|
||||
- allocation to succeed for the test to work. */
|
||||
- DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
|
||||
-#endif
|
||||
- char *path = malloc (path_len);
|
||||
- DIAG_POP_NEEDS_COMMENT;
|
||||
+ struct support_blob_repeat repeat
|
||||
+ = support_blob_repeat_allocate ("a", 1, path_len);
|
||||
+ char *path = repeat.start;
|
||||
if (path == NULL)
|
||||
{
|
||||
- printf ("malloc (%zu): %m\n", path_len);
|
||||
+ printf ("Repeated allocation (%zu bytes): %m\n", path_len);
|
||||
/* On 31-bit s390 the malloc will always fail as we do not have
|
||||
so much memory, and we want to mark the test unsupported.
|
||||
Likewise on systems with little physical memory the test will
|
||||
@@ -62,7 +58,6 @@ do_test (void)
|
||||
/* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */
|
||||
char *p = mempcpy (path, lnk, strlen (lnk));
|
||||
*(p++) = '/';
|
||||
- memset (p, 'a', path_len - (p - path) - 2);
|
||||
p[path_len - (p - path) - 1] = '\0';
|
||||
|
||||
/* This call crashes before the fix for bz22786 on 32-bit platforms. */
|
||||
@@ -76,6 +71,7 @@ do_test (void)
|
||||
|
||||
/* Cleanup. */
|
||||
unlink (lnk);
|
||||
+ support_blob_repeat_free (&repeat);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
commit 07da99aad93c9364acb7efdab47c27ba698f6313
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Oct 30 13:55:01 2018 +0100
|
||||
|
||||
stdlib/tst-strtod-overflow: Switch to support_blob_repeat
|
||||
|
||||
This is another test with an avoidable large memory allocation.
|
||||
|
||||
diff --git a/stdlib/tst-strtod-overflow.c b/stdlib/tst-strtod-overflow.c
|
||||
index d14638d68ef4f471..dc53c1e521443e1d 100644
|
||||
--- a/stdlib/tst-strtod-overflow.c
|
||||
+++ b/stdlib/tst-strtod-overflow.c
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
+#include <support/blob_repeat.h>
|
||||
+#include <support/test-driver.h>
|
||||
|
||||
#define EXPONENT "e-2147483649"
|
||||
#define SIZE 214748364
|
||||
@@ -26,21 +28,23 @@
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
- char *p = malloc (1 + SIZE + sizeof (EXPONENT));
|
||||
- if (p == NULL)
|
||||
+ struct support_blob_repeat repeat = support_blob_repeat_allocate
|
||||
+ ("0", 1, 1 + SIZE + sizeof (EXPONENT));
|
||||
+ if (repeat.size == 0)
|
||||
{
|
||||
- puts ("malloc failed, cannot test for overflow");
|
||||
- return 0;
|
||||
+ puts ("warning: memory allocation failed, cannot test for overflow");
|
||||
+ return EXIT_UNSUPPORTED;
|
||||
}
|
||||
+ char *p = repeat.start;
|
||||
p[0] = '1';
|
||||
- memset (p + 1, '0', SIZE);
|
||||
memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT));
|
||||
double d = strtod (p, NULL);
|
||||
if (d != 0)
|
||||
{
|
||||
- printf ("strtod returned wrong value: %a\n", d);
|
||||
+ printf ("error: strtod returned wrong value: %a\n", d);
|
||||
return 1;
|
||||
}
|
||||
+ support_blob_repeat_free (&repeat);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
commit 60708030536df82616c16aa2f14f533c4362b969
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Oct 30 13:56:40 2018 +0100
|
||||
|
||||
stdlib/test-bz22786: Avoid memory leaks in the test itself
|
||||
|
||||
diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c
|
||||
index bb1e04f2debe9042..8035e8a394e7d034 100644
|
||||
--- a/stdlib/test-bz22786.c
|
||||
+++ b/stdlib/test-bz22786.c
|
||||
@@ -36,8 +36,8 @@
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
- const char *dir = support_create_temp_directory ("bz22786.");
|
||||
- const char *lnk = xasprintf ("%s/symlink", dir);
|
||||
+ char *dir = support_create_temp_directory ("bz22786.");
|
||||
+ char *lnk = xasprintf ("%s/symlink", dir);
|
||||
const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1;
|
||||
|
||||
struct support_blob_repeat repeat
|
||||
@@ -72,6 +72,8 @@ do_test (void)
|
||||
/* Cleanup. */
|
||||
unlink (lnk);
|
||||
support_blob_repeat_free (&repeat);
|
||||
+ free (lnk);
|
||||
+ free (dir);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
commit f9b645b4b0a10c43753296ce3fa40053fa44606a
|
||||
Author: Mike Frysinger <vapier@gentoo.org>
|
||||
Date: Wed Apr 24 13:32:22 2019 +0200
|
||||
|
||||
memusagestat: use local glibc when linking [BZ #18465]
|
||||
|
||||
The memusagestat is the only binary that has its own link line which
|
||||
causes it to be linked against the existing installed C library. It
|
||||
has been this way since it was originally committed in 1999, but I
|
||||
don't see any reason as to why. Since we want all the programs we
|
||||
build locally to be against the new copy of glibc, change the build
|
||||
to be like all other programs.
|
||||
|
||||
diff --git a/malloc/Makefile b/malloc/Makefile
|
||||
index 388cf7e9ee3a2569..228a1279a5960d8c 100644
|
||||
--- a/malloc/Makefile
|
||||
+++ b/malloc/Makefile
|
||||
@@ -131,6 +131,7 @@ ifneq ($(cross-compiling),yes)
|
||||
# If the gd library is available we build the `memusagestat' program.
|
||||
ifneq ($(LIBGD),no)
|
||||
others: $(objpfx)memusage
|
||||
+others += memusagestat
|
||||
install-bin = memusagestat
|
||||
install-bin-script += memusage
|
||||
generated += memusagestat memusage
|
||||
@@ -154,8 +155,7 @@ cpp-srcs-left := $(memusagestat-modules)
|
||||
lib := memusagestat
|
||||
include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
|
||||
|
||||
-$(objpfx)memusagestat: $(memusagestat-modules:%=$(objpfx)%.o)
|
||||
- $(LINK.o) -o $@ $^ $(libgd-LDFLAGS) -lgd -lpng -lz -lm
|
||||
+LDLIBS-memusagestat = $(libgd-LDFLAGS) -lgd -lpng -lz -lm
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
ifeq (yes,$(build-shared))
|
@ -0,0 +1,90 @@
|
||||
commit 94a4e9e4f401ffe829a992820439977ead0a0ce7
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Apr 25 10:41:43 2019 +0200
|
||||
|
||||
Extend BIND_NOW to installed programs with --enable-bind-now
|
||||
|
||||
Commit 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9 ("Document and fix
|
||||
--enable-bind-now [BZ #21015]") extended BIND_NOW to all installed
|
||||
shared objects. This change also covers installed programs.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/INSTALL b/INSTALL
|
||||
index d6c8e899fbb47dac..d56e102ec9ed3281 100644
|
||||
--- a/INSTALL
|
||||
+++ b/INSTALL
|
||||
@@ -169,10 +169,10 @@ if 'CFLAGS' is specified it must enable optimization. For example:
|
||||
protection.
|
||||
|
||||
'--enable-bind-now'
|
||||
- Disable lazy binding for installed shared objects. This provides
|
||||
- additional security hardening because it enables full RELRO and a
|
||||
- read-only global offset table (GOT), at the cost of slightly
|
||||
- increased program load times.
|
||||
+ Disable lazy binding for installed shared objects and programs.
|
||||
+ This provides additional security hardening because it enables full
|
||||
+ RELRO and a read-only global offset table (GOT), at the cost of
|
||||
+ slightly increased program load times.
|
||||
|
||||
'--enable-pt_chown'
|
||||
The file 'pt_chown' is a helper binary for 'grantpt' (*note
|
||||
diff --git a/Makeconfig b/Makeconfig
|
||||
index 8dc2fec9dc683416..742c0c0783a14bfa 100644
|
||||
--- a/Makeconfig
|
||||
+++ b/Makeconfig
|
||||
@@ -398,6 +398,8 @@ endif
|
||||
# test modules.
|
||||
ifeq ($(bind-now),yes)
|
||||
LDFLAGS-lib.so += -Wl,-z,now
|
||||
+# Extra flags for dynamically linked non-test main programs.
|
||||
+link-extra-flags += -Wl,-z,now
|
||||
endif
|
||||
|
||||
# Command to run after every final link (executable or shared object).
|
||||
@@ -426,7 +428,7 @@ ifndef +link-pie
|
||||
$(link-extra-libs)
|
||||
+link-pie-after-libc = $(+postctorS) $(+postinit)
|
||||
define +link-pie
|
||||
-$(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-pie-after-libc)
|
||||
+$(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-pie-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-pie-tests
|
||||
@@ -454,7 +456,7 @@ ifndef +link-static
|
||||
$(link-extra-libs-static)
|
||||
+link-static-after-libc = $(+postctorT) $(+postinit)
|
||||
define +link-static
|
||||
-$(+link-static-before-libc) $(link-libc-static) $(+link-static-after-libc)
|
||||
+$(+link-static-before-libc) $(link-extra-flags) $(link-libc-static) $(+link-static-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-static-tests
|
||||
@@ -485,7 +487,7 @@ else # not build-pie-default
|
||||
$(link-extra-libs)
|
||||
+link-after-libc = $(+postctor) $(+postinit)
|
||||
define +link
|
||||
-$(+link-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-after-libc)
|
||||
+$(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-tests
|
||||
diff --git a/manual/install.texi b/manual/install.texi
|
||||
index e757891dc2eebb2e..351d67c68b255f62 100644
|
||||
--- a/manual/install.texi
|
||||
+++ b/manual/install.texi
|
||||
@@ -199,10 +199,10 @@ number of routines called directly from assembler are excluded from this
|
||||
protection.
|
||||
|
||||
@item --enable-bind-now
|
||||
-Disable lazy binding for installed shared objects. This provides
|
||||
-additional security hardening because it enables full RELRO and a
|
||||
-read-only global offset table (GOT), at the cost of slightly increased
|
||||
-program load times.
|
||||
+Disable lazy binding for installed shared objects and programs. This
|
||||
+provides additional security hardening because it enables full RELRO
|
||||
+and a read-only global offset table (GOT), at the cost of slightly
|
||||
+increased program load times.
|
||||
|
||||
@pindex pt_chown
|
||||
@findex grantpt
|
@ -0,0 +1,43 @@
|
||||
commit b5ffdc48c20ae865b197b67e5a9068a528fbc198
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Apr 25 10:41:52 2019 +0200
|
||||
|
||||
benchtests: Enable BIND_NOW if configured with --enable-bind-now
|
||||
|
||||
Benchmarks should reflect distribution build policies, so it makes
|
||||
sense to honor the BIND_NOW configuration for them.
|
||||
|
||||
This commit keeps using $(+link-tests), so that the benchmarks are
|
||||
linked according to the --enable-hardcoded-path-in-tests configure
|
||||
option.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/benchtests/Makefile b/benchtests/Makefile
|
||||
index bcd6a9c26d9a0005..28d6b0c43f5bd390 100644
|
||||
--- a/benchtests/Makefile
|
||||
+++ b/benchtests/Makefile
|
||||
@@ -235,13 +235,21 @@ bench-func: $(binaries-bench)
|
||||
scripts/benchout.schema.json; \
|
||||
fi
|
||||
|
||||
-$(timing-type) $(binaries-bench) $(binaries-benchset) \
|
||||
- $(binaries-bench-malloc): %: %.o $(objpfx)json-lib.o \
|
||||
+ifeq ($(bind-now),yes)
|
||||
+link-bench-bind-now = -Wl,-z,now
|
||||
+endif
|
||||
+
|
||||
+bench-link-targets = $(timing-type) $(binaries-bench) $(binaries-benchset) \
|
||||
+ $(binaries-bench-malloc)
|
||||
+
|
||||
+$(bench-link-targets): %: %.o $(objpfx)json-lib.o \
|
||||
$(link-extra-libs-tests) \
|
||||
$(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
|
||||
$(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
|
||||
$(+link-tests)
|
||||
|
||||
+$(bench-link-targets): LDFLAGS += $(link-bench-bind-now)
|
||||
+
|
||||
$(objpfx)bench-%.c: %-inputs $(bench-deps)
|
||||
{ if [ -n "$($*-INCLUDE)" ]; then \
|
||||
cat $($*-INCLUDE); \
|
@ -0,0 +1,100 @@
|
||||
commit e30fb31c0ad8d31babd1d0d0f05e37c6579a870b
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Apr 26 07:16:47 2019 +0200
|
||||
|
||||
Makeconfig: Move $(CC) to +link command variables
|
||||
|
||||
This change is needed to add linker flags which come very early in the
|
||||
command linke (before LDFLAGS) and are not applied to test programs
|
||||
(only to installed programs).
|
||||
|
||||
diff --git a/Makeconfig b/Makeconfig
|
||||
index 742c0c0783a14bfa..1ad25fc5a7251aea 100644
|
||||
--- a/Makeconfig
|
||||
+++ b/Makeconfig
|
||||
@@ -415,7 +415,7 @@ link-extra-libs-tests = $(libsupport)
|
||||
|
||||
# Command for linking PIE programs with the C library.
|
||||
ifndef +link-pie
|
||||
-+link-pie-before-libc = $(CC) $(if $($(@F)-no-pie),$(no-pie-ldflag),-pie) \
|
||||
++link-pie-before-libc = $(if $($(@F)-no-pie),$(no-pie-ldflag),-pie) \
|
||||
-Wl,-O1 -nostdlib -nostartfiles -o $@ \
|
||||
$(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
|
||||
$(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
|
||||
@@ -428,23 +428,24 @@ ifndef +link-pie
|
||||
$(link-extra-libs)
|
||||
+link-pie-after-libc = $(+postctorS) $(+postinit)
|
||||
define +link-pie
|
||||
-$(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-pie-after-libc)
|
||||
+$(CC) $(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) \
|
||||
+ $(link-libc) $(+link-pie-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-pie-tests
|
||||
-$(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
|
||||
- $(+link-pie-after-libc)
|
||||
+$(CC) $(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
|
||||
+ $(+link-pie-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-pie-printers-tests
|
||||
-$(+link-pie-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \
|
||||
- $(+link-pie-after-libc)
|
||||
+$(CC) $(+link-pie-before-libc) $(built-rtld-LDFLAGS) \
|
||||
+ $(link-libc-printers-tests) $(+link-pie-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
endif
|
||||
# Command for statically linking programs with the C library.
|
||||
ifndef +link-static
|
||||
-+link-static-before-libc = $(CC) -nostdlib -nostartfiles -static -o $@ \
|
||||
++link-static-before-libc = -nostdlib -nostartfiles -static -o $@ \
|
||||
$(if $($(@F)-no-pie),$(no-pie-ldflag),$(default-pie-ldflag)) \
|
||||
$(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
|
||||
$(firstword $(CRT-$(@F)) $(csu-objpfx)$(real-static-start-installed-name)) \
|
||||
@@ -456,11 +457,13 @@ ifndef +link-static
|
||||
$(link-extra-libs-static)
|
||||
+link-static-after-libc = $(+postctorT) $(+postinit)
|
||||
define +link-static
|
||||
-$(+link-static-before-libc) $(link-extra-flags) $(link-libc-static) $(+link-static-after-libc)
|
||||
+$(CC) $(+link-static-before-libc) $(link-extra-flags) $(link-libc-static) \
|
||||
+ $(+link-static-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-static-tests
|
||||
-$(+link-static-before-libc) $(link-libc-static-tests) $(+link-static-after-libc)
|
||||
+$(CC) $(+link-static-before-libc) $(link-libc-static-tests) \
|
||||
+ $(+link-static-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
endif
|
||||
@@ -475,7 +478,7 @@ ifeq (yes,$(build-pie-default))
|
||||
+link-tests = $(+link-pie-tests)
|
||||
+link-printers-tests = $(+link-pie-printers-tests)
|
||||
else # not build-pie-default
|
||||
-+link-before-libc = $(CC) -nostdlib -nostartfiles -o $@ \
|
||||
++link-before-libc = -nostdlib -nostartfiles -o $@ \
|
||||
$(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
|
||||
$(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
|
||||
$(firstword $(CRT-$(@F)) $(csu-objpfx)$(start-installed-name)) \
|
||||
@@ -487,16 +490,17 @@ else # not build-pie-default
|
||||
$(link-extra-libs)
|
||||
+link-after-libc = $(+postctor) $(+postinit)
|
||||
define +link
|
||||
-$(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) $(+link-after-libc)
|
||||
+$(CC) $(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) \
|
||||
+ $(+link-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-tests
|
||||
-$(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
|
||||
+$(CC) $(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
|
||||
$(+link-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-printers-tests
|
||||
-$(+link-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \
|
||||
+$(CC) $(+link-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \
|
||||
$(+link-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
@ -0,0 +1,74 @@
|
||||
commit a8ff215e56050a907189e713fd449bcafe99ff6b
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Apr 26 07:16:30 2019 +0200
|
||||
|
||||
Makeconfig: Move -Wl,-rpath-link options before library references
|
||||
|
||||
Previously, the -Wl,-rpath-link options came after the libraries
|
||||
injected using LDLIBS-* variables on the link editor command line for
|
||||
main programs. As a result, it could happen that installed libraries
|
||||
that reference glibc libraries used the installed glibc from the system
|
||||
directories, instead of the glibc from the build tree. This can lead to
|
||||
link failures if the wrong version of libpthread.so.0 is used, for
|
||||
instance, due to differences in the internal GLIBC_PRIVATE interfaces,
|
||||
as seen with memusagestat and -lgd after commit
|
||||
f9b645b4b0a10c43753296ce3fa40053fa44606a ("memusagestat: use local glibc
|
||||
when linking [BZ #18465]").
|
||||
|
||||
The isolation is necessarily imperfect because these installed
|
||||
libraries are linked against the installed glibc in the system
|
||||
directories. However, in most cases, the built glibc will be newer
|
||||
than the installed glibc, and this link is permitted because of the
|
||||
ABI backwards compatibility glibc provides.
|
||||
|
||||
diff --git a/Makeconfig b/Makeconfig
|
||||
index 1ad25fc5a7251aea..e315fb8a75ca5063 100644
|
||||
--- a/Makeconfig
|
||||
+++ b/Makeconfig
|
||||
@@ -428,8 +428,8 @@ ifndef +link-pie
|
||||
$(link-extra-libs)
|
||||
+link-pie-after-libc = $(+postctorS) $(+postinit)
|
||||
define +link-pie
|
||||
-$(CC) $(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) \
|
||||
- $(link-libc) $(+link-pie-after-libc)
|
||||
+$(CC) $(link-libc-rpath-link) $(+link-pie-before-libc) $(rtld-LDFLAGS) \
|
||||
+ $(link-extra-flags) $(link-libc) $(+link-pie-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-pie-tests
|
||||
@@ -490,8 +490,8 @@ else # not build-pie-default
|
||||
$(link-extra-libs)
|
||||
+link-after-libc = $(+postctor) $(+postinit)
|
||||
define +link
|
||||
-$(CC) $(+link-before-libc) $(rtld-LDFLAGS) $(link-extra-flags) $(link-libc) \
|
||||
- $(+link-after-libc)
|
||||
+$(CC) $(link-libc-rpath-link) $(+link-before-libc) $(rtld-LDFLAGS) \
|
||||
+ $(link-extra-flags) $(link-libc) $(+link-after-libc)
|
||||
$(call after-link,$@)
|
||||
endef
|
||||
define +link-tests
|
||||
@@ -552,6 +552,15 @@ ifeq (yes,$(build-shared))
|
||||
link-libc-rpath = -Wl,-rpath=$(rpath-link)
|
||||
link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
|
||||
|
||||
+# For programs which are not tests, $(link-libc-rpath-link) is added
|
||||
+# directly in $(+link), $(+link-pie) above, so that -Wl,-rpath-link
|
||||
+# comes before the expansion of LDLIBS-* and affects libraries added
|
||||
+# there. For shared objects, -Wl,-rpath-link is added via
|
||||
+# $(build-shlib-helper) and $(build-module-helper) in Makerules (also
|
||||
+# before the expansion of LDLIBS-* variables).
|
||||
+
|
||||
+# Tests use -Wl,-rpath instead of -Wl,-rpath-link for
|
||||
+# build-hardcoded-path-in-tests.
|
||||
ifeq (yes,$(build-hardcoded-path-in-tests))
|
||||
link-libc-tests-rpath-link = $(link-libc-rpath)
|
||||
else
|
||||
@@ -562,7 +571,7 @@ link-libc-before-gnulib = $(common-objpfx)libc.so$(libc.so-version) \
|
||||
$(common-objpfx)$(patsubst %,$(libtype.oS),c) \
|
||||
$(as-needed) $(elf-objpfx)ld.so \
|
||||
$(no-as-needed)
|
||||
-link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib)
|
||||
+link-libc = $(link-libc-before-gnulib) $(gnulib)
|
||||
|
||||
link-libc-tests-after-rpath-link = $(link-libc-before-gnulib) $(gnulib-tests)
|
||||
link-libc-tests = $(link-libc-tests-rpath-link) \
|
@ -0,0 +1,25 @@
|
||||
commit c57afec0a9b318bb691e0f5fa4e9681cf30df7a4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Apr 26 07:16:56 2019 +0200
|
||||
|
||||
elf: Link sotruss-lib.so with BIND_NOW for --enable-bind-now
|
||||
|
||||
The audit module itself can be linked with BIND_NOW; it does not
|
||||
affect its functionality.
|
||||
|
||||
This should complete the leftovers from commit
|
||||
2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9 ("Document and fix
|
||||
--enable-bind-now [BZ #21015]").
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index f5285b99e22fe84d..9194339836900b9d 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -133,6 +133,7 @@ install-others += $(inst_auditdir)/sotruss-lib.so
|
||||
install-bin-script += sotruss
|
||||
generated += sotruss
|
||||
libof-sotruss-lib = extramodules
|
||||
+LDFLAGS-sotruss-lib.so += $(z-now-$(bind-now))
|
||||
$(objpfx)sotruss-lib.so: $(objpfx)sotruss-lib.os
|
||||
$(build-module-asneeded)
|
||||
$(objpfx)sotruss-lib.so: $(common-objpfx)libc.so $(objpfx)ld.so \
|
@ -0,0 +1,41 @@
|
||||
commit c3d8dc45c9df199b8334599a6cbd98c9950dba62
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Thu Oct 11 15:18:40 2018 -0300
|
||||
|
||||
x86: Fix Haswell strong flags (BZ#23709)
|
||||
|
||||
Th commit 'Disable TSX on some Haswell processors.' (2702856bf4) changed the
|
||||
default flags for Haswell models. Previously, new models were handled by the
|
||||
default switch path, which assumed a Core i3/i5/i7 if AVX is available. After
|
||||
the patch, Haswell models (0x3f, 0x3c, 0x45, 0x46) do not set the flags
|
||||
Fast_Rep_String, Fast_Unaligned_Load, Fast_Unaligned_Copy, and
|
||||
Prefer_PMINUB_for_stringop (only the TSX one).
|
||||
|
||||
This patch fixes it by disentangle the TSX flag handling from the memory
|
||||
optimization ones. The strstr case cited on patch now selects the
|
||||
__strstr_sse2_unaligned as expected for the Haswell cpu.
|
||||
|
||||
Checked on x86_64-linux-gnu.
|
||||
|
||||
[BZ #23709]
|
||||
* sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits
|
||||
independently of other flags.
|
||||
|
||||
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
|
||||
index ea0b64fdb962a934..4695ac80d4148327 100644
|
||||
--- a/sysdeps/x86/cpu-features.c
|
||||
+++ b/sysdeps/x86/cpu-features.c
|
||||
@@ -316,7 +316,13 @@ init_cpu_features (struct cpu_features *cpu_features)
|
||||
| bit_arch_Fast_Unaligned_Copy
|
||||
| bit_arch_Prefer_PMINUB_for_stringop);
|
||||
break;
|
||||
+ }
|
||||
|
||||
+ /* Disable TSX on some Haswell processors to avoid TSX on kernels that
|
||||
+ weren't updated with the latest microcode package (which disables
|
||||
+ broken feature by default). */
|
||||
+ switch (model)
|
||||
+ {
|
||||
case 0x3f:
|
||||
/* Xeon E7 v3 with stepping >= 4 has working TSX. */
|
||||
if (stepping >= 4)
|
@ -0,0 +1,230 @@
|
||||
commit bcdaad21d4635931d1bd3b54a7894276925d081d
|
||||
Author: DJ Delorie <dj@delorie.com>
|
||||
Date: Tue Nov 20 13:24:09 2018 -0500
|
||||
|
||||
malloc: tcache double free check
|
||||
|
||||
* malloc/malloc.c (tcache_entry): Add key field.
|
||||
(tcache_put): Set it.
|
||||
(tcache_get): Likewise.
|
||||
(_int_free): Check for double free in tcache.
|
||||
* malloc/tst-tcfree1.c: New.
|
||||
* malloc/tst-tcfree2.c: New.
|
||||
* malloc/Makefile: Run the new tests.
|
||||
* manual/probes.texi: Document memory_tcache_double_free probe.
|
||||
|
||||
* dlfcn/dlerror.c (check_free): Prevent double frees.
|
||||
|
||||
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
|
||||
index 33574faab65628ff..96bf92533335036b 100644
|
||||
--- a/dlfcn/dlerror.c
|
||||
+++ b/dlfcn/dlerror.c
|
||||
@@ -198,7 +198,10 @@ check_free (struct dl_action_result *rec)
|
||||
Dl_info info;
|
||||
if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
|
||||
#endif
|
||||
- free ((char *) rec->errstring);
|
||||
+ {
|
||||
+ free ((char *) rec->errstring);
|
||||
+ rec->errstring = NULL;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/malloc/Makefile b/malloc/Makefile
|
||||
index 7d54bad866f63cb8..e6dfbfc14cb3d140 100644
|
||||
--- a/malloc/Makefile
|
||||
+++ b/malloc/Makefile
|
||||
@@ -38,6 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-malloc_info \
|
||||
tst-malloc-too-large \
|
||||
tst-malloc-stats-cancellation \
|
||||
+ tst-tcfree1 tst-tcfree2 \
|
||||
|
||||
tests-static := \
|
||||
tst-interpose-static-nothread \
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index e247c77b7d4de26e..c6b0282e783eaeea 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -2888,6 +2888,8 @@ mremap_chunk (mchunkptr p, size_t new_size)
|
||||
typedef struct tcache_entry
|
||||
{
|
||||
struct tcache_entry *next;
|
||||
+ /* This field exists to detect double frees. */
|
||||
+ struct tcache_perthread_struct *key;
|
||||
} tcache_entry;
|
||||
|
||||
/* There is one of these for each thread, which contains the
|
||||
@@ -2911,6 +2913,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
|
||||
{
|
||||
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
|
||||
assert (tc_idx < TCACHE_MAX_BINS);
|
||||
+
|
||||
+ /* Mark this chunk as "in the tcache" so the test in _int_free will
|
||||
+ detect a double free. */
|
||||
+ e->key = tcache;
|
||||
+
|
||||
e->next = tcache->entries[tc_idx];
|
||||
tcache->entries[tc_idx] = e;
|
||||
++(tcache->counts[tc_idx]);
|
||||
@@ -2926,6 +2933,7 @@ tcache_get (size_t tc_idx)
|
||||
assert (tcache->entries[tc_idx] > 0);
|
||||
tcache->entries[tc_idx] = e->next;
|
||||
--(tcache->counts[tc_idx]);
|
||||
+ e->key = NULL;
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
@@ -4152,6 +4160,26 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
{
|
||||
size_t tc_idx = csize2tidx (size);
|
||||
|
||||
+ /* Check to see if it's already in the tcache. */
|
||||
+ tcache_entry *e = (tcache_entry *) chunk2mem (p);
|
||||
+
|
||||
+ /* This test succeeds on double free. However, we don't 100%
|
||||
+ trust it (it also matches random payload data at a 1 in
|
||||
+ 2^<size_t> chance), so verify it's not an unlikely coincidence
|
||||
+ before aborting. */
|
||||
+ if (__glibc_unlikely (e->key == tcache && tcache))
|
||||
+ {
|
||||
+ tcache_entry *tmp;
|
||||
+ LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
|
||||
+ for (tmp = tcache->entries[tc_idx];
|
||||
+ tmp;
|
||||
+ tmp = tmp->next)
|
||||
+ if (tmp == e)
|
||||
+ malloc_printerr ("free(): double free detected in tcache 2");
|
||||
+ /* If we get here, it was a coincidence. We've wasted a few
|
||||
+ cycles, but don't abort. */
|
||||
+ }
|
||||
+
|
||||
if (tcache
|
||||
&& tc_idx < mp_.tcache_bins
|
||||
&& tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..bc29375ce77304ac
|
||||
--- /dev/null
|
||||
+++ b/malloc/tst-tcfree1.c
|
||||
@@ -0,0 +1,42 @@
|
||||
+/* Test that malloc tcache catches double free.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <error.h>
|
||||
+#include <limits.h>
|
||||
+#include <malloc.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <stdio.h>
|
||||
+#include <sys/signal.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Do one allocation of any size that fits in tcache. */
|
||||
+ char * volatile x = malloc (32);
|
||||
+
|
||||
+ free (x); // puts in tcache
|
||||
+ free (x); // should abort
|
||||
+
|
||||
+ printf("FAIL: tcache double free not detected\n");
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+#define TEST_FUNCTION do_test
|
||||
+#define EXPECTED_SIGNAL SIGABRT
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..17f06bacd411c315
|
||||
--- /dev/null
|
||||
+++ b/malloc/tst-tcfree2.c
|
||||
@@ -0,0 +1,48 @@
|
||||
+/* Test that malloc tcache catches double free.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <error.h>
|
||||
+#include <limits.h>
|
||||
+#include <malloc.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <stdio.h>
|
||||
+#include <sys/signal.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ char * volatile ptrs[20];
|
||||
+ int i;
|
||||
+
|
||||
+ /* Allocate enough small chunks so that when we free them all, the tcache
|
||||
+ is full, and the first one we freed is at the end of its linked list. */
|
||||
+#define COUNT 20
|
||||
+ for (i=0; i<COUNT; i++)
|
||||
+ ptrs[i] = malloc (20);
|
||||
+ for (i=0; i<COUNT; i++)
|
||||
+ free (ptrs[i]);
|
||||
+ free (ptrs[0]);
|
||||
+
|
||||
+ printf("FAIL: tcache double free\n");
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+#define TEST_FUNCTION do_test
|
||||
+#define EXPECTED_SIGNAL SIGABRT
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/manual/probes.texi b/manual/probes.texi
|
||||
index ab2a3102bb350ef4..0ea560ed78bcfd7e 100644
|
||||
--- a/manual/probes.texi
|
||||
+++ b/manual/probes.texi
|
||||
@@ -243,6 +243,18 @@ This probe is triggered when the
|
||||
value of this tunable.
|
||||
@end deftp
|
||||
|
||||
+@deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2})
|
||||
+This probe is triggered when @code{free} determines that the memory
|
||||
+being freed has probably already been freed, and resides in the
|
||||
+per-thread cache. Note that there is an extremely unlikely chance
|
||||
+that this probe will trigger due to random payload data remaining in
|
||||
+the allocated memory matching the key used to detect double frees.
|
||||
+This probe actually indicates that an expensive linear search of the
|
||||
+tcache, looking for a double free, has happened. Argument @var{$arg1}
|
||||
+is the memory location as passed to @code{free}, Argument @var{$arg2}
|
||||
+is the tcache bin it resides in.
|
||||
+@end deftp
|
||||
+
|
||||
@node Mathematical Function Probes
|
||||
@section Mathematical Function Probes
|
||||
|
@ -0,0 +1,73 @@
|
||||
commit affec03b713c82c43a5b025dddc21bde3334f41e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Nov 26 20:06:37 2018 +0100
|
||||
|
||||
malloc: tcache: Validate tc_idx before checking for double-frees [BZ #23907]
|
||||
|
||||
The previous check could read beyond the end of the tcache entry
|
||||
array. If the e->key == tcache cookie check happened to pass, this
|
||||
would result in crashes.
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index c6b0282e783eaeea..13c52f376859562d 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -4159,33 +4159,33 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
#if USE_TCACHE
|
||||
{
|
||||
size_t tc_idx = csize2tidx (size);
|
||||
-
|
||||
- /* Check to see if it's already in the tcache. */
|
||||
- tcache_entry *e = (tcache_entry *) chunk2mem (p);
|
||||
-
|
||||
- /* This test succeeds on double free. However, we don't 100%
|
||||
- trust it (it also matches random payload data at a 1 in
|
||||
- 2^<size_t> chance), so verify it's not an unlikely coincidence
|
||||
- before aborting. */
|
||||
- if (__glibc_unlikely (e->key == tcache && tcache))
|
||||
+ if (tcache != NULL && tc_idx < mp_.tcache_bins)
|
||||
{
|
||||
- tcache_entry *tmp;
|
||||
- LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
|
||||
- for (tmp = tcache->entries[tc_idx];
|
||||
- tmp;
|
||||
- tmp = tmp->next)
|
||||
- if (tmp == e)
|
||||
- malloc_printerr ("free(): double free detected in tcache 2");
|
||||
- /* If we get here, it was a coincidence. We've wasted a few
|
||||
- cycles, but don't abort. */
|
||||
- }
|
||||
+ /* Check to see if it's already in the tcache. */
|
||||
+ tcache_entry *e = (tcache_entry *) chunk2mem (p);
|
||||
+
|
||||
+ /* This test succeeds on double free. However, we don't 100%
|
||||
+ trust it (it also matches random payload data at a 1 in
|
||||
+ 2^<size_t> chance), so verify it's not an unlikely
|
||||
+ coincidence before aborting. */
|
||||
+ if (__glibc_unlikely (e->key == tcache))
|
||||
+ {
|
||||
+ tcache_entry *tmp;
|
||||
+ LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
|
||||
+ for (tmp = tcache->entries[tc_idx];
|
||||
+ tmp;
|
||||
+ tmp = tmp->next)
|
||||
+ if (tmp == e)
|
||||
+ malloc_printerr ("free(): double free detected in tcache 2");
|
||||
+ /* If we get here, it was a coincidence. We've wasted a
|
||||
+ few cycles, but don't abort. */
|
||||
+ }
|
||||
|
||||
- if (tcache
|
||||
- && tc_idx < mp_.tcache_bins
|
||||
- && tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
- {
|
||||
- tcache_put (p, tc_idx);
|
||||
- return;
|
||||
+ if (tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
+ {
|
||||
+ tcache_put (p, tc_idx);
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,89 @@
|
||||
commit 7c9a7c68363051cfc5fa1ebb96b3b2c1f82dcb76
|
||||
Author: DJ Delorie <dj@redhat.com>
|
||||
Date: Fri Nov 30 22:13:09 2018 -0500
|
||||
|
||||
malloc: Add another test for tcache double free check.
|
||||
|
||||
This one tests for BZ#23907 where the double free
|
||||
test didn't check the tcache bin bounds before dereferencing
|
||||
the bin.
|
||||
|
||||
[BZ #23907]
|
||||
* malloc/tst-tcfree3.c: New.
|
||||
* malloc/Makefile: Add it.
|
||||
|
||||
diff --git a/malloc/Makefile b/malloc/Makefile
|
||||
index e6dfbfc14cb3d140..388cf7e9ee3a2569 100644
|
||||
--- a/malloc/Makefile
|
||||
+++ b/malloc/Makefile
|
||||
@@ -38,7 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-malloc_info \
|
||||
tst-malloc-too-large \
|
||||
tst-malloc-stats-cancellation \
|
||||
- tst-tcfree1 tst-tcfree2 \
|
||||
+ tst-tcfree1 tst-tcfree2 tst-tcfree3 \
|
||||
|
||||
tests-static := \
|
||||
tst-interpose-static-nothread \
|
||||
diff --git a/malloc/tst-tcfree3.c b/malloc/tst-tcfree3.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..016d30ddd8114082
|
||||
--- /dev/null
|
||||
+++ b/malloc/tst-tcfree3.c
|
||||
@@ -0,0 +1,56 @@
|
||||
+/* Test that malloc tcache catches double free.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <malloc.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+/* Prevent GCC from optimizing away any malloc/free pairs. */
|
||||
+#pragma GCC optimize ("O0")
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Do two allocation of any size that fit in tcache, and one that
|
||||
+ doesn't. */
|
||||
+ int ** volatile a = malloc (32);
|
||||
+ int ** volatile b = malloc (32);
|
||||
+ /* This is just under the mmap threshold. */
|
||||
+ int ** volatile c = malloc (127 * 1024);
|
||||
+
|
||||
+ /* The invalid "tcache bucket" we might dereference will likely end
|
||||
+ up somewhere within this memory block, so make all the accidental
|
||||
+ "next" pointers cause segfaults. BZ #23907. */
|
||||
+ memset (c, 0xff, 127 * 1024);
|
||||
+
|
||||
+ free (a); // puts in tcache
|
||||
+
|
||||
+ /* A is now free and contains the key we use to detect in-tcache.
|
||||
+ Copy the key to the other chunks. */
|
||||
+ memcpy (b, a, 32);
|
||||
+ memcpy (c, a, 32);
|
||||
+
|
||||
+ /* This free tests the "are we in the tcache already" loop with a
|
||||
+ VALID bin but "coincidental" matching key. */
|
||||
+ free (b); // should NOT abort
|
||||
+ /* This free tests the "is it a valid tcache bin" test. */
|
||||
+ free (c); // should NOT abort
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
@ -0,0 +1,176 @@
|
||||
commit a803367bab167f5ec4fde1f0d0ec447707c29520
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Feb 14 20:55:39 2020 +0100
|
||||
|
||||
powerpc64: Add memory protection key support [BZ #23202]
|
||||
|
||||
The 32-bit protection key behavior is somewhat unclear on 32-bit powerpc,
|
||||
so this change is restricted to the 64-bit variants.
|
||||
|
||||
Flag translation is needed because of hardware differences between the
|
||||
POWER implementation (read and write flags) and the Intel implementation
|
||||
(write and read+write flags).
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h
|
||||
new file mode 100644
|
||||
index 0000000000000000..623b073d5a585d51
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h
|
||||
@@ -0,0 +1,55 @@
|
||||
+/* Helper functions for manipulating memory protection keys, for powerpc64.
|
||||
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifndef _ARCH_PKEY_H
|
||||
+#define _ARCH_PKEY_H
|
||||
+
|
||||
+/* Read and write access bits in the AMR register. Needs to be
|
||||
+ translated from and to PKEY_DISABLE_* flags. */
|
||||
+#define PKEY_AMR_READ 1UL
|
||||
+#define PKEY_AMR_WRITE 2UL
|
||||
+
|
||||
+/* Return the value of the AMR register. */
|
||||
+static inline unsigned long int
|
||||
+pkey_read (void)
|
||||
+{
|
||||
+ unsigned long int result;
|
||||
+ __asm__ volatile ("mfspr %0, 13" : "=r" (result));
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+/* Overwrite the AMR register with VALUE. */
|
||||
+static inline void
|
||||
+pkey_write (unsigned long int value)
|
||||
+{
|
||||
+ __asm__ volatile ("mtspr 13, %0" : : "r" (value));
|
||||
+}
|
||||
+
|
||||
+/* Number of the largest supported key. This depends on the width of
|
||||
+ the AMR register. */
|
||||
+#define PKEY_MAX (sizeof (unsigned long int) * 8 / 2 - 1)
|
||||
+_Static_assert (PKEY_MAX == 15 || PKEY_MAX == 31, "PKEY_MAX value");
|
||||
+
|
||||
+/* Translate key number into AMR index position. */
|
||||
+static inline int
|
||||
+pkey_index (int key)
|
||||
+{
|
||||
+ return 2 * (PKEY_MAX - key);
|
||||
+}
|
||||
+
|
||||
+#endif /* _ARCH_PKEY_H */
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..856ba061b90eabd2
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c
|
||||
@@ -0,0 +1,42 @@
|
||||
+/* Reading the per-thread memory protection key, powerpc64 version.
|
||||
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <arch-pkey.h>
|
||||
+#include <errno.h>
|
||||
+#include <sys/mman.h>
|
||||
+
|
||||
+int
|
||||
+pkey_get (int key)
|
||||
+{
|
||||
+ if (key < 0 || key > PKEY_MAX)
|
||||
+ {
|
||||
+ __set_errno (EINVAL);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ unsigned int index = pkey_index (key);
|
||||
+ unsigned long int amr = pkey_read ();
|
||||
+ unsigned int bits = (amr >> index) & 3;
|
||||
+
|
||||
+ /* Translate from AMR values. PKEY_AMR_READ standing alone is not
|
||||
+ currently representable. */
|
||||
+ if (bits & PKEY_AMR_READ)
|
||||
+ return PKEY_DISABLE_ACCESS;
|
||||
+ else if (bits == PKEY_AMR_WRITE)
|
||||
+ return PKEY_DISABLE_WRITE;
|
||||
+ return 0;
|
||||
+}
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..20b372ee2983abd5
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c
|
||||
@@ -0,0 +1,48 @@
|
||||
+/* Changing the per-thread memory protection key, powerpc64 version.
|
||||
+ Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <arch-pkey.h>
|
||||
+#include <errno.h>
|
||||
+#include <sys/mman.h>
|
||||
+
|
||||
+int
|
||||
+pkey_set (int key, unsigned int rights)
|
||||
+{
|
||||
+ if (key < 0 || key > PKEY_MAX || rights > 3)
|
||||
+ {
|
||||
+ __set_errno (EINVAL);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ /* Translate to AMR bit values. */
|
||||
+ unsigned long int bits;
|
||||
+ if (rights & PKEY_DISABLE_ACCESS)
|
||||
+ /* The PKEY_DISABLE_WRITE bit does not matter. */
|
||||
+ bits = PKEY_AMR_READ | PKEY_AMR_WRITE;
|
||||
+ else if (rights == PKEY_DISABLE_WRITE)
|
||||
+ bits = PKEY_AMR_WRITE;
|
||||
+ else
|
||||
+ bits = 0;
|
||||
+
|
||||
+ unsigned int index = pkey_index (key);
|
||||
+ unsigned long int mask = 3UL << index;
|
||||
+ unsigned long int amr = pkey_read ();
|
||||
+ amr = (amr & ~mask) | (bits << index);
|
||||
+ pkey_write (amr);
|
||||
+ return 0;
|
||||
+}
|
@ -0,0 +1,53 @@
|
||||
commit 8d42bf859a289944749d9f978c076cd318119867
|
||||
Author: Lucas A. M. Magalhaes <lamm@linux.ibm.com>
|
||||
Date: Mon Feb 17 09:09:52 2020 -0300
|
||||
|
||||
Fix tst-pkey expectations on pkey_get [BZ #23202]
|
||||
|
||||
From the GNU C Library manual, the pkey_set can receive a combination of
|
||||
PKEY_DISABLE_WRITE and PKEY_DISABLE_ACCESS. However PKEY_DISABLE_ACCESS
|
||||
is more restrictive than PKEY_DISABLE_WRITE and includes its behavior.
|
||||
|
||||
The test expects that after setting
|
||||
(PKEY_DISABLE_WRITE|PKEY_DISABLE_ACCESS) pkey_get should return the
|
||||
same. This may not be true as PKEY_DISABLE_ACCESS will succeed in
|
||||
describing the state of the key in this case.
|
||||
|
||||
The pkey behavior during signal handling is different between x86 and
|
||||
POWER. This change make the test compatible with both architectures.
|
||||
|
||||
Reviewed-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-pkey.c b/sysdeps/unix/sysv/linux/tst-pkey.c
|
||||
index 5f721d4444490945..600b6f0098def773 100644
|
||||
--- a/sysdeps/unix/sysv/linux/tst-pkey.c
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-pkey.c
|
||||
@@ -37,7 +37,7 @@ static pthread_barrier_t barrier;
|
||||
|
||||
/* The keys used for testing. These have been allocated with access
|
||||
rights set based on their array index. */
|
||||
-enum { key_count = 4 };
|
||||
+enum { key_count = 3 };
|
||||
static int keys[key_count];
|
||||
static volatile int *pages[key_count];
|
||||
|
||||
@@ -111,14 +111,16 @@ check_page_access (int page, bool write)
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t sigusr1_handler_ran;
|
||||
-
|
||||
-/* Used to check that access is revoked in signal handlers. */
|
||||
+/* Used to check the behavior in signal handlers. In x86 all access are
|
||||
+ revoked during signal handling. In PowerPC the key permissions are
|
||||
+ inherited by the interrupted thread. This test accept both approaches. */
|
||||
static void
|
||||
sigusr1_handler (int signum)
|
||||
{
|
||||
TEST_COMPARE (signum, SIGUSR1);
|
||||
for (int i = 0; i < key_count; ++i)
|
||||
- TEST_COMPARE (pkey_get (keys[i]), PKEY_DISABLE_ACCESS);
|
||||
+ TEST_VERIFY (pkey_get (keys[i]) == PKEY_DISABLE_ACCESS
|
||||
+ || pkey_get (keys[i]) == i);
|
||||
sigusr1_handler_ran = 1;
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
commit 70ba28f7ab2923d4e36ffc9d5d2e32357353b25c
|
||||
Author: Lucas A. M. Magalhaes <lamm@linux.ibm.com>
|
||||
Date: Thu Jan 16 10:39:12 2020 -0300
|
||||
|
||||
Fix tst-pkey.c pkey_alloc return checks and manual
|
||||
|
||||
This test was failing in some powerpc systems as it was not checking
|
||||
for ENOSPC return.
|
||||
|
||||
As said on the Linux man-pages and can be observed by the implementation
|
||||
at mm/mprotect.c in the Linux Kernel source. The syscall pkey_alloc can
|
||||
return EINVAL or ENOSPC. ENOSPC will indicate either that all keys are
|
||||
in use or that the kernel does not support pkeys.
|
||||
|
||||
Reviewed-by: Gabriel F. T. Gomes <gabriel@inconstante.net.br>
|
||||
|
||||
diff --git a/manual/memory.texi b/manual/memory.texi
|
||||
index a1435aad1acd3239..4731a38bcc5701e0 100644
|
||||
--- a/manual/memory.texi
|
||||
+++ b/manual/memory.texi
|
||||
@@ -3289,6 +3289,10 @@ in which memory protection keys are disabled.
|
||||
|
||||
@item ENOSPC
|
||||
All available protection keys already have been allocated.
|
||||
+
|
||||
+The system does not implement memory protection keys or runs in a mode
|
||||
+in which memory protection keys are disabled.
|
||||
+
|
||||
@end table
|
||||
@end deftypefun
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-pkey.c b/sysdeps/unix/sysv/linux/tst-pkey.c
|
||||
index 600b6f0098def773..40d7e9f24dec3e57 100644
|
||||
--- a/sysdeps/unix/sysv/linux/tst-pkey.c
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-pkey.c
|
||||
@@ -199,6 +199,10 @@ do_test (void)
|
||||
if (errno == EINVAL)
|
||||
FAIL_UNSUPPORTED
|
||||
("CPU does not support memory protection keys: %m");
|
||||
+ if (errno == ENOSPC)
|
||||
+ FAIL_UNSUPPORTED
|
||||
+ ("no keys available or kernel does not support memory"
|
||||
+ " protection keys");
|
||||
FAIL_EXIT1 ("pkey_alloc: %m");
|
||||
}
|
||||
TEST_COMPARE (pkey_get (keys[0]), 0);
|
@ -0,0 +1,36 @@
|
||||
commit e627106266ad8785457fadbf5bf67ed604d2a353
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon May 11 11:20:02 2020 +0200
|
||||
|
||||
POWER: Add context-synchronizing instructions to pkey_write [BZ #25954]
|
||||
|
||||
Sandipan Das reported that,
|
||||
|
||||
"The Power ISA mandates that all writes to the Authority
|
||||
Mask Register (AMR) must always be preceded as well as
|
||||
succeeded by a context-synchronizing instruction. This
|
||||
applies to both the privileged and unprivileged variants
|
||||
of the Move To AMR instruction.
|
||||
|
||||
This [requirement] is from Table 6 of Chapter 11 in page 1134 of Power
|
||||
ISA 3.0B. The document can be found here:
|
||||
<https://ibm.ent.box.com/s/1hzcwkwf8rbju5h9iyf44wm94amnlcrv>
|
||||
"
|
||||
|
||||
See this kernel patch submission:
|
||||
|
||||
<https://lore.kernel.org/linuxppc-dev/5f65cf37be993760de8112a88da194e3ccbb2bf8.1588959697.git.sandipan@linux.ibm.com/>
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h
|
||||
index 623b073d5a585d51..25d080c9a6f30942 100644
|
||||
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h
|
||||
@@ -37,7 +37,7 @@ pkey_read (void)
|
||||
static inline void
|
||||
pkey_write (unsigned long int value)
|
||||
{
|
||||
- __asm__ volatile ("mtspr 13, %0" : : "r" (value));
|
||||
+ __asm__ volatile ("isync; mtspr 13, %0; isync" : : "r" (value));
|
||||
}
|
||||
|
||||
/* Number of the largest supported key. This depends on the width of
|
@ -0,0 +1,34 @@
|
||||
commit 28669f86f6780a18daca264f32d66b1428c9c6f1
|
||||
Author: Stefan Liebler <stli@linux.ibm.com>
|
||||
Date: Thu Sep 6 14:27:03 2018 +0200
|
||||
|
||||
Fix segfault in maybe_script_execute.
|
||||
|
||||
If glibc is built with gcc 8 and -march=z900,
|
||||
the testcase posix/tst-spawn4-compat crashes with a segfault.
|
||||
|
||||
In function maybe_script_execute, the new_argv array is dynamically
|
||||
initialized on stack with (argc + 1) elements.
|
||||
The function wants to add _PATH_BSHELL as the first argument
|
||||
and writes out of bounds of new_argv.
|
||||
There is an off-by-one because maybe_script_execute fails to count
|
||||
the terminating NULL when sizing new_argv.
|
||||
|
||||
ChangeLog:
|
||||
|
||||
* sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute):
|
||||
Increment size of new_argv by one.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
|
||||
index cf0213ece55c675d..85239cedbf2a5ab5 100644
|
||||
--- a/sysdeps/unix/sysv/linux/spawni.c
|
||||
+++ b/sysdeps/unix/sysv/linux/spawni.c
|
||||
@@ -101,7 +101,7 @@ maybe_script_execute (struct posix_spawn_args *args)
|
||||
ptrdiff_t argc = args->argc;
|
||||
|
||||
/* Construct an argument list for the shell. */
|
||||
- char *new_argv[argc + 1];
|
||||
+ char *new_argv[argc + 2];
|
||||
new_argv[0] = (char *) _PATH_BSHELL;
|
||||
new_argv[1] = (char *) args->file;
|
||||
if (argc > 1)
|
@ -0,0 +1,193 @@
|
||||
commit 7a16bdbb9ff4122af0a28dc20996c95352011fdd
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Wed Aug 29 16:36:44 2018 -0300
|
||||
|
||||
Fix misreported errno on preadv2/pwritev2 (BZ#23579)
|
||||
|
||||
The fallback code of Linux wrapper for preadv2/pwritev2 executes
|
||||
regardless of the errno code for preadv2, instead of the case where
|
||||
the syscall is not supported.
|
||||
|
||||
This fixes it by calling the fallback code iff errno is ENOSYS. The
|
||||
patch also adds tests for both invalid file descriptor and invalid
|
||||
iov_len and vector count.
|
||||
|
||||
The only discrepancy between preadv2 and fallback code regarding
|
||||
error reporting is when an invalid flags are used. The fallback code
|
||||
bails out earlier with ENOTSUP instead of EINVAL/EBADF when the syscall
|
||||
is used.
|
||||
|
||||
Checked on x86_64-linux-gnu on a 4.4.0 and 4.15.0 kernel.
|
||||
|
||||
[BZ #23579]
|
||||
* misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd): New
|
||||
test.
|
||||
* misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test):
|
||||
Call do_test_with_invalid_fd.
|
||||
* sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff
|
||||
errno is ENOSYS.
|
||||
* sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise.
|
||||
* sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise.
|
||||
* sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise.
|
||||
|
||||
diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c
|
||||
index f889a21544947042..50b9da3fea56d288 100644
|
||||
--- a/misc/tst-preadvwritev2-common.c
|
||||
+++ b/misc/tst-preadvwritev2-common.c
|
||||
@@ -19,9 +19,6 @@
|
||||
#include <limits.h>
|
||||
#include <support/check.h>
|
||||
|
||||
-static void
|
||||
-do_test_with_invalid_flags (void)
|
||||
-{
|
||||
#ifndef RWF_HIPRI
|
||||
# define RWF_HIPRI 0
|
||||
#endif
|
||||
@@ -39,6 +36,68 @@ do_test_with_invalid_flags (void)
|
||||
#endif
|
||||
#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
|
||||
| RWF_APPEND)
|
||||
+
|
||||
+static void
|
||||
+do_test_with_invalid_fd (void)
|
||||
+{
|
||||
+ char buf[256];
|
||||
+ struct iovec iov = { buf, sizeof buf };
|
||||
+
|
||||
+ /* Check with flag being 0 to use the fallback code which calls pwritev
|
||||
+ or writev. */
|
||||
+ TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1);
|
||||
+ TEST_COMPARE (errno, EBADF);
|
||||
+ TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1);
|
||||
+ TEST_COMPARE (errno, EBADF);
|
||||
+
|
||||
+ /* Same tests as before but with flags being different than 0. Since
|
||||
+ there is no emulation for any flag value, fallback code returns
|
||||
+ ENOTSUP. This is different running on a kernel with preadv2/pwritev2
|
||||
+ support, where EBADF is returned). */
|
||||
+ TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
|
||||
+ TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+do_test_with_invalid_iov (void)
|
||||
+{
|
||||
+ {
|
||||
+ char buf[256];
|
||||
+ struct iovec iov;
|
||||
+
|
||||
+ iov.iov_base = buf;
|
||||
+ iov.iov_len = (size_t)SSIZE_MAX + 1;
|
||||
+
|
||||
+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1);
|
||||
+ TEST_COMPARE (errno, EINVAL);
|
||||
+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1);
|
||||
+ TEST_COMPARE (errno, EINVAL);
|
||||
+
|
||||
+ /* Same as for invalid file descriptor tests, emulation fallback
|
||||
+ first checks for flag value and return ENOTSUP. */
|
||||
+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
+ }
|
||||
+
|
||||
+ {
|
||||
+ /* An invalid iovec buffer should trigger an invalid memory access
|
||||
+ or an error (Linux for instance returns EFAULT). */
|
||||
+ struct iovec iov[IOV_MAX+1] = { 0 };
|
||||
+
|
||||
+ TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
|
||||
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
+ TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
|
||||
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+do_test_with_invalid_flags (void)
|
||||
+{
|
||||
/* Set the next bit from the mask of all supported flags. */
|
||||
int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2;
|
||||
invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag);
|
||||
diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c
|
||||
index be22802dbe00317f..cb58cbe41ecc639d 100644
|
||||
--- a/misc/tst-preadvwritev2.c
|
||||
+++ b/misc/tst-preadvwritev2.c
|
||||
@@ -30,6 +30,8 @@ do_test (void)
|
||||
{
|
||||
do_test_with_invalid_flags ();
|
||||
do_test_without_offset ();
|
||||
+ do_test_with_invalid_fd ();
|
||||
+ do_test_with_invalid_iov ();
|
||||
|
||||
return do_test_with_offset (0);
|
||||
}
|
||||
diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c
|
||||
index 8d3cc32b284dbf4c..6a9de54c786acc53 100644
|
||||
--- a/misc/tst-preadvwritev64v2.c
|
||||
+++ b/misc/tst-preadvwritev64v2.c
|
||||
@@ -32,6 +32,8 @@ do_test (void)
|
||||
{
|
||||
do_test_with_invalid_flags ();
|
||||
do_test_without_offset ();
|
||||
+ do_test_with_invalid_fd ();
|
||||
+ do_test_with_invalid_iov ();
|
||||
|
||||
return do_test_with_offset (0);
|
||||
}
|
||||
diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c
|
||||
index c8bf0764ef2629fc..bb08cbc5fd96962e 100644
|
||||
--- a/sysdeps/unix/sysv/linux/preadv2.c
|
||||
+++ b/sysdeps/unix/sysv/linux/preadv2.c
|
||||
@@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset,
|
||||
# ifdef __NR_preadv2
|
||||
ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
- if (result >= 0)
|
||||
+ if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
# endif
|
||||
/* Trying to emulate the preadv2 syscall flags is troublesome:
|
||||
diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c
|
||||
index d7400a0252a8c6a1..b72a047347b1db0e 100644
|
||||
--- a/sysdeps/unix/sysv/linux/preadv64v2.c
|
||||
+++ b/sysdeps/unix/sysv/linux/preadv64v2.c
|
||||
@@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
|
||||
#ifdef __NR_preadv64v2
|
||||
ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
- if (result >= 0)
|
||||
+ if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
#endif
|
||||
/* Trying to emulate the preadv2 syscall flags is troublesome:
|
||||
diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c
|
||||
index 29c2264c8f3d949a..26333ebd43c5f0af 100644
|
||||
--- a/sysdeps/unix/sysv/linux/pwritev2.c
|
||||
+++ b/sysdeps/unix/sysv/linux/pwritev2.c
|
||||
@@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset,
|
||||
# ifdef __NR_pwritev2
|
||||
ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
- if (result >= 0)
|
||||
+ if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
# endif
|
||||
/* Trying to emulate the pwritev2 syscall flags is troublesome:
|
||||
diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c
|
||||
index 42da321149bce40d..17ea905aa6a8db94 100644
|
||||
--- a/sysdeps/unix/sysv/linux/pwritev64v2.c
|
||||
+++ b/sysdeps/unix/sysv/linux/pwritev64v2.c
|
||||
@@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
|
||||
#ifdef __NR_pwritev64v2
|
||||
ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
- if (result >= 0)
|
||||
+ if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
#endif
|
||||
/* Trying to emulate the pwritev2 syscall flags is troublesome:
|
@ -0,0 +1,33 @@
|
||||
commit dae3ed958c3d0090838e49ff4f78c201262b1cf0
|
||||
Author: Rafal Luzynski <digitalfreak@lingonborough.com>
|
||||
Date: Tue Oct 2 23:34:18 2018 +0200
|
||||
|
||||
kl_GL: Fix spelling of Sunday, should be "sapaat" (bug 20209).
|
||||
|
||||
Although CLDR says otherwise, it is confirmed by Oqaasileriffik, the
|
||||
official Greenlandic language regulator, that this change is correct.
|
||||
|
||||
[BZ #20209]
|
||||
* localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday),
|
||||
should be "sap" rather than "sab".
|
||||
(day): Fix spelling of Sunday, should be "sapaat" rather than
|
||||
"sabaat".
|
||||
|
||||
diff --git a/localedata/locales/kl_GL b/localedata/locales/kl_GL
|
||||
index 5ab14a31aade8644..5723ce7dcf9c5742 100644
|
||||
--- a/localedata/locales/kl_GL
|
||||
+++ b/localedata/locales/kl_GL
|
||||
@@ -70,11 +70,11 @@ copy "da_DK"
|
||||
END LC_NUMERIC
|
||||
|
||||
LC_TIME
|
||||
-abday "sab";"ata";/
|
||||
+abday "sap";"ata";/
|
||||
"mar";"pin";/
|
||||
"sis";"tal";/
|
||||
"arf"
|
||||
-day "sabaat";/
|
||||
+day "sapaat";/
|
||||
"ataasinngorneq";/
|
||||
"marlunngorneq";/
|
||||
"pingasunngorneq";/
|
@ -0,0 +1,134 @@
|
||||
commit 7b1f9406761331cf35fe521fbdb592beecf68a2c
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Fri Sep 28 13:31:19 2018 -0700
|
||||
|
||||
i386: Use _dl_runtime_[resolve|profile]_shstk for SHSTK [BZ #23716]
|
||||
|
||||
When elf_machine_runtime_setup is called to set up resolver, it should
|
||||
use _dl_runtime_resolve_shstk or _dl_runtime_profile_shstk if SHSTK is
|
||||
enabled by kernel.
|
||||
|
||||
Tested on i686 with and without --enable-cet as well as on CET emulator
|
||||
with --enable-cet.
|
||||
|
||||
[BZ #23716]
|
||||
* sysdeps/i386/dl-cet.c: Removed.
|
||||
* sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New
|
||||
prototype.
|
||||
(_dl_runtime_profile_shstk): Likewise.
|
||||
(elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or
|
||||
_dl_runtime_resolve_shstk if SHSTK is enabled by kernel.
|
||||
|
||||
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
|
||||
diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c
|
||||
deleted file mode 100644
|
||||
index 5d9a4e8d5179b572..0000000000000000
|
||||
--- a/sysdeps/i386/dl-cet.c
|
||||
+++ /dev/null
|
||||
@@ -1,67 +0,0 @@
|
||||
-/* Linux/i386 CET initializers function.
|
||||
- Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
-
|
||||
- The GNU C Library is free software; you can redistribute it and/or
|
||||
- modify it under the terms of the GNU Lesser General Public
|
||||
- License as published by the Free Software Foundation; either
|
||||
- version 2.1 of the License, or (at your option) any later version.
|
||||
-
|
||||
- The GNU C Library is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
- Lesser General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Lesser General Public
|
||||
- License along with the GNU C Library; if not, see
|
||||
- <http://www.gnu.org/licenses/>. */
|
||||
-
|
||||
-
|
||||
-#define LINKAGE static inline
|
||||
-#define _dl_cet_check cet_check
|
||||
-#include <sysdeps/x86/dl-cet.c>
|
||||
-#undef _dl_cet_check
|
||||
-
|
||||
-#ifdef SHARED
|
||||
-void
|
||||
-_dl_cet_check (struct link_map *main_map, const char *program)
|
||||
-{
|
||||
- cet_check (main_map, program);
|
||||
-
|
||||
- if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
|
||||
- {
|
||||
- /* Replace _dl_runtime_resolve and _dl_runtime_profile with
|
||||
- _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk,
|
||||
- respectively if SHSTK is enabled. */
|
||||
- extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
|
||||
- extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
|
||||
- extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
|
||||
- extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
|
||||
- unsigned int i;
|
||||
- struct link_map *l;
|
||||
- Elf32_Addr *got;
|
||||
-
|
||||
- if (main_map->l_info[DT_JMPREL])
|
||||
- {
|
||||
- got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]);
|
||||
- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve)
|
||||
- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk;
|
||||
- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile)
|
||||
- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk;
|
||||
- }
|
||||
-
|
||||
- i = main_map->l_searchlist.r_nlist;
|
||||
- while (i-- > 0)
|
||||
- {
|
||||
- l = main_map->l_initfini[i];
|
||||
- if (l->l_info[DT_JMPREL])
|
||||
- {
|
||||
- got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
|
||||
- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve)
|
||||
- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk;
|
||||
- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile)
|
||||
- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-#endif
|
||||
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
|
||||
index 1afdcbd9ea2626e4..f6cfb90e21015250 100644
|
||||
--- a/sysdeps/i386/dl-machine.h
|
||||
+++ b/sysdeps/i386/dl-machine.h
|
||||
@@ -67,6 +67,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
Elf32_Addr *got;
|
||||
extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
|
||||
extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
|
||||
+ extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
|
||||
+ extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
|
||||
+ /* Check if SHSTK is enabled by kernel. */
|
||||
+ bool shstk_enabled
|
||||
+ = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
|
||||
|
||||
if (l->l_info[DT_JMPREL] && lazy)
|
||||
{
|
||||
@@ -93,7 +98,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
end in this function. */
|
||||
if (__glibc_unlikely (profile))
|
||||
{
|
||||
- got[2] = (Elf32_Addr) &_dl_runtime_profile;
|
||||
+ got[2] = (shstk_enabled
|
||||
+ ? (Elf32_Addr) &_dl_runtime_profile_shstk
|
||||
+ : (Elf32_Addr) &_dl_runtime_profile);
|
||||
|
||||
if (GLRO(dl_profile) != NULL
|
||||
&& _dl_name_match_p (GLRO(dl_profile), l))
|
||||
@@ -104,7 +111,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
else
|
||||
/* This function will get called to fix up the GOT entry indicated by
|
||||
the offset on the stack, and then jump to the resolved address. */
|
||||
- got[2] = (Elf32_Addr) &_dl_runtime_resolve;
|
||||
+ got[2] = (shstk_enabled
|
||||
+ ? (Elf32_Addr) &_dl_runtime_resolve_shstk
|
||||
+ : (Elf32_Addr) &_dl_runtime_resolve);
|
||||
}
|
||||
|
||||
return lazy;
|
@ -0,0 +1,738 @@
|
||||
commit 403b4feb22dcbc85ace72a361d2a951380372471
|
||||
Author: Stefan Liebler <stli@linux.ibm.com>
|
||||
Date: Wed Oct 17 12:23:04 2018 +0200
|
||||
|
||||
Fix race in pthread_mutex_lock while promoting to PTHREAD_MUTEX_ELISION_NP [BZ #23275]
|
||||
|
||||
The race leads either to pthread_mutex_destroy returning EBUSY
|
||||
or triggering an assertion (See description in bugzilla).
|
||||
|
||||
This patch is fixing the race by ensuring that the elision path is
|
||||
used in all cases if elision is enabled by the GLIBC_TUNABLES framework.
|
||||
|
||||
The __kind variable in struct __pthread_mutex_s is accessed concurrently.
|
||||
Therefore we are now using the atomic macros.
|
||||
|
||||
The new testcase tst-mutex10 is triggering the race on s390x and intel.
|
||||
Presumably also on power, but I don't have access to a power machine
|
||||
with lock-elision. At least the code for power is the same as on the other
|
||||
two architectures.
|
||||
|
||||
ChangeLog:
|
||||
|
||||
[BZ #23275]
|
||||
* nptl/tst-mutex10.c: New File.
|
||||
* nptl/Makefile (tests): Add tst-mutex10.
|
||||
(tst-mutex10-ENV): New variable.
|
||||
* sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION):
|
||||
Ensure that elision path is used if elision is available.
|
||||
* sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION):
|
||||
Likewise.
|
||||
* sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION):
|
||||
Likewise.
|
||||
* nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION)
|
||||
(PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed.
|
||||
* nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise.
|
||||
* nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling):
|
||||
Likewise.
|
||||
* nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full)
|
||||
(__pthread_mutex_cond_lock_adjust): Likewise.
|
||||
* nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling):
|
||||
Likewise.
|
||||
* nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise.
|
||||
* nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise.
|
||||
* nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise.
|
||||
* sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s):
|
||||
Add comments.
|
||||
* nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy):
|
||||
Use atomic_load_relaxed and atomic_store_relaxed.
|
||||
* nptl/pthread_mutex_init.c (__pthread_mutex_init):
|
||||
Use atomic_store_relaxed.
|
||||
|
||||
diff --git a/nptl/Makefile b/nptl/Makefile
|
||||
index be8066524cdc57db..49b6faa330c492e0 100644
|
||||
--- a/nptl/Makefile
|
||||
+++ b/nptl/Makefile
|
||||
@@ -241,9 +241,9 @@ LDLIBS-tst-minstack-throw = -lstdc++
|
||||
|
||||
tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
|
||||
tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
|
||||
- tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \
|
||||
- tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
|
||||
- tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
|
||||
+ tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \
|
||||
+ tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \
|
||||
+ tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
|
||||
tst-mutexpi9 \
|
||||
tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
|
||||
tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
|
||||
@@ -709,6 +709,8 @@ endif
|
||||
|
||||
$(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so
|
||||
|
||||
+tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1
|
||||
+
|
||||
# The tests here better do not run in parallel
|
||||
ifneq ($(filter %tests,$(MAKECMDGOALS)),)
|
||||
.NOTPARALLEL:
|
||||
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
|
||||
index 13bdb11133536195..19efe1e35feed5be 100644
|
||||
--- a/nptl/pthreadP.h
|
||||
+++ b/nptl/pthreadP.h
|
||||
@@ -110,19 +110,23 @@ enum
|
||||
};
|
||||
#define PTHREAD_MUTEX_PSHARED_BIT 128
|
||||
|
||||
+/* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
#define PTHREAD_MUTEX_TYPE(m) \
|
||||
- ((m)->__data.__kind & 127)
|
||||
+ (atomic_load_relaxed (&((m)->__data.__kind)) & 127)
|
||||
/* Don't include NO_ELISION, as that type is always the same
|
||||
as the underlying lock type. */
|
||||
#define PTHREAD_MUTEX_TYPE_ELISION(m) \
|
||||
- ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP))
|
||||
+ (atomic_load_relaxed (&((m)->__data.__kind)) \
|
||||
+ & (127 | PTHREAD_MUTEX_ELISION_NP))
|
||||
|
||||
#if LLL_PRIVATE == 0 && LLL_SHARED == 128
|
||||
# define PTHREAD_MUTEX_PSHARED(m) \
|
||||
- ((m)->__data.__kind & 128)
|
||||
+ (atomic_load_relaxed (&((m)->__data.__kind)) & 128)
|
||||
#else
|
||||
# define PTHREAD_MUTEX_PSHARED(m) \
|
||||
- (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE)
|
||||
+ ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \
|
||||
+ ? LLL_SHARED : LLL_PRIVATE)
|
||||
#endif
|
||||
|
||||
/* The kernel when waking robust mutexes on exit never uses
|
||||
diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c
|
||||
index 85b8e1a6cb027e9b..4fbd875430439e4d 100644
|
||||
--- a/nptl/pthread_mutex_consistent.c
|
||||
+++ b/nptl/pthread_mutex_consistent.c
|
||||
@@ -23,8 +23,11 @@
|
||||
int
|
||||
pthread_mutex_consistent (pthread_mutex_t *mutex)
|
||||
{
|
||||
- /* Test whether this is a robust mutex with a dead owner. */
|
||||
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
|
||||
+ /* Test whether this is a robust mutex with a dead owner.
|
||||
+ See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
|
||||
|| mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT)
|
||||
return EINVAL;
|
||||
|
||||
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
|
||||
index 5a22611541995778..713ea684962fefc1 100644
|
||||
--- a/nptl/pthread_mutex_destroy.c
|
||||
+++ b/nptl/pthread_mutex_destroy.c
|
||||
@@ -27,12 +27,17 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex)
|
||||
{
|
||||
LIBC_PROBE (mutex_destroy, 1, mutex);
|
||||
|
||||
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
|
||||
&& mutex->__data.__nusers != 0)
|
||||
return EBUSY;
|
||||
|
||||
- /* Set to an invalid value. */
|
||||
- mutex->__data.__kind = -1;
|
||||
+ /* Set to an invalid value. Relaxed MO is enough as it is undefined behavior
|
||||
+ if the mutex is used after it has been destroyed. But you can reinitialize
|
||||
+ it with pthread_mutex_init. */
|
||||
+ atomic_store_relaxed (&(mutex->__data.__kind), -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c
|
||||
index efa37b0d99201f57..ee85949578475f3a 100644
|
||||
--- a/nptl/pthread_mutex_getprioceiling.c
|
||||
+++ b/nptl/pthread_mutex_getprioceiling.c
|
||||
@@ -24,7 +24,9 @@
|
||||
int
|
||||
pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling)
|
||||
{
|
||||
- if (__builtin_expect ((mutex->__data.__kind
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
& PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0))
|
||||
return EINVAL;
|
||||
|
||||
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
|
||||
index d8fe4737289c0bd7..5cf290c272e27915 100644
|
||||
--- a/nptl/pthread_mutex_init.c
|
||||
+++ b/nptl/pthread_mutex_init.c
|
||||
@@ -101,7 +101,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
|
||||
memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
|
||||
|
||||
/* Copy the values from the attribute. */
|
||||
- mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
|
||||
+ int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
|
||||
|
||||
if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
|
||||
{
|
||||
@@ -111,17 +111,17 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
|
||||
return ENOTSUP;
|
||||
#endif
|
||||
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
}
|
||||
|
||||
switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
|
||||
{
|
||||
case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
|
||||
+ mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
|
||||
break;
|
||||
|
||||
case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
|
||||
+ mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
|
||||
|
||||
int ceiling = (imutexattr->mutexkind
|
||||
& PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
|
||||
@@ -145,7 +145,11 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
|
||||
FUTEX_PRIVATE_FLAG FUTEX_WAKE. */
|
||||
if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED
|
||||
| PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0)
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT;
|
||||
+ mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT;
|
||||
+
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind);
|
||||
|
||||
/* Default values: mutex not used yet. */
|
||||
// mutex->__count = 0; already done by memset
|
||||
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
|
||||
index 1519c142bd6ec5cc..29cc143e6cbf2421 100644
|
||||
--- a/nptl/pthread_mutex_lock.c
|
||||
+++ b/nptl/pthread_mutex_lock.c
|
||||
@@ -62,6 +62,8 @@ static int __pthread_mutex_lock_full (pthread_mutex_t *mutex)
|
||||
int
|
||||
__pthread_mutex_lock (pthread_mutex_t *mutex)
|
||||
{
|
||||
+ /* See concurrency notes regarding mutex type which is loaded from __kind
|
||||
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
|
||||
|
||||
LIBC_PROBE (mutex_entry, 1, mutex);
|
||||
@@ -350,8 +352,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
|
||||
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
|
||||
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
|
||||
{
|
||||
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ int kind, robust;
|
||||
+ {
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
|
||||
+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ }
|
||||
|
||||
if (robust)
|
||||
{
|
||||
@@ -502,7 +510,10 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
|
||||
case PTHREAD_MUTEX_PP_NORMAL_NP:
|
||||
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
|
||||
{
|
||||
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int kind = atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
|
||||
oldval = mutex->__data.__lock;
|
||||
|
||||
@@ -607,15 +618,18 @@ hidden_def (__pthread_mutex_lock)
|
||||
void
|
||||
__pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex)
|
||||
{
|
||||
- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
|
||||
- assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
|
||||
- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
|
||||
+ assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
|
||||
+ assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
|
||||
+ assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
|
||||
|
||||
/* Record the ownership. */
|
||||
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
|
||||
mutex->__data.__owner = id;
|
||||
|
||||
- if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
|
||||
+ if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
|
||||
++mutex->__data.__count;
|
||||
}
|
||||
#endif
|
||||
diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c
|
||||
index 8594874f8588b7a8..8306cabcf4e56174 100644
|
||||
--- a/nptl/pthread_mutex_setprioceiling.c
|
||||
+++ b/nptl/pthread_mutex_setprioceiling.c
|
||||
@@ -27,9 +27,10 @@ int
|
||||
pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
|
||||
int *old_ceiling)
|
||||
{
|
||||
- /* The low bits of __kind aren't ever changed after pthread_mutex_init,
|
||||
- so we don't need a lock yet. */
|
||||
- if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
|
||||
return EINVAL;
|
||||
|
||||
/* See __init_sched_fifo_prio. */
|
||||
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
|
||||
index 28237b0e58cfcaf5..888c12fe28b2ebfd 100644
|
||||
--- a/nptl/pthread_mutex_timedlock.c
|
||||
+++ b/nptl/pthread_mutex_timedlock.c
|
||||
@@ -53,6 +53,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
|
||||
/* We must not check ABSTIME here. If the thread does not block
|
||||
abstime must not be checked for a valid value. */
|
||||
|
||||
+ /* See concurrency notes regarding mutex type which is loaded from __kind
|
||||
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
|
||||
PTHREAD_MUTEX_TIMED_NP))
|
||||
{
|
||||
@@ -338,8 +340,14 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
|
||||
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
|
||||
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
|
||||
{
|
||||
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ int kind, robust;
|
||||
+ {
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
|
||||
+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ }
|
||||
|
||||
if (robust)
|
||||
{
|
||||
@@ -509,7 +517,10 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
|
||||
case PTHREAD_MUTEX_PP_NORMAL_NP:
|
||||
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
|
||||
{
|
||||
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int kind = atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
|
||||
oldval = mutex->__data.__lock;
|
||||
|
||||
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
|
||||
index 7de61f4f688c1537..fa90c1d1e6f5afc2 100644
|
||||
--- a/nptl/pthread_mutex_trylock.c
|
||||
+++ b/nptl/pthread_mutex_trylock.c
|
||||
@@ -36,6 +36,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
|
||||
int oldval;
|
||||
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
|
||||
|
||||
+ /* See concurrency notes regarding mutex type which is loaded from __kind
|
||||
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
|
||||
PTHREAD_MUTEX_TIMED_NP))
|
||||
{
|
||||
@@ -199,8 +201,14 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
|
||||
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
|
||||
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
|
||||
{
|
||||
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ int kind, robust;
|
||||
+ {
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
|
||||
+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ }
|
||||
|
||||
if (robust)
|
||||
/* Note: robust PI futexes are signaled by setting bit 0. */
|
||||
@@ -325,7 +333,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
|
||||
case PTHREAD_MUTEX_PP_NORMAL_NP:
|
||||
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
|
||||
{
|
||||
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int kind = atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_KIND_MASK_NP;
|
||||
|
||||
oldval = mutex->__data.__lock;
|
||||
|
||||
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
|
||||
index 9ea62943b7c6b159..68d04d53955584e5 100644
|
||||
--- a/nptl/pthread_mutex_unlock.c
|
||||
+++ b/nptl/pthread_mutex_unlock.c
|
||||
@@ -35,6 +35,8 @@ int
|
||||
attribute_hidden
|
||||
__pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr)
|
||||
{
|
||||
+ /* See concurrency notes regarding mutex type which is loaded from __kind
|
||||
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
|
||||
if (__builtin_expect (type &
|
||||
~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0))
|
||||
@@ -222,13 +224,19 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
|
||||
/* If the previous owner died and the caller did not succeed in
|
||||
making the state consistent, mark the mutex as unrecoverable
|
||||
and make all waiters. */
|
||||
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
|
||||
&& __builtin_expect (mutex->__data.__owner
|
||||
== PTHREAD_MUTEX_INCONSISTENT, 0))
|
||||
pi_notrecoverable:
|
||||
newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
|
||||
|
||||
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
|
||||
{
|
||||
continue_pi_robust:
|
||||
/* Remove mutex from the list.
|
||||
@@ -251,7 +259,10 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
|
||||
/* Unlock. Load all necessary mutex data before releasing the mutex
|
||||
to not violate the mutex destruction requirements (see
|
||||
lll_unlock). */
|
||||
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
|
||||
+ in sysdeps/nptl/bits/thread-shared-types.h. */
|
||||
+ int robust = atomic_load_relaxed (&(mutex->__data.__kind))
|
||||
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
private = (robust
|
||||
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
|
||||
: PTHREAD_MUTEX_PSHARED (mutex));
|
||||
diff --git a/nptl/tst-mutex10.c b/nptl/tst-mutex10.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..e1113ca60a7c8db5
|
||||
--- /dev/null
|
||||
+++ b/nptl/tst-mutex10.c
|
||||
@@ -0,0 +1,109 @@
|
||||
+/* Testing race while enabling lock elision.
|
||||
+ Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
+ This file is part of the GNU C Library.
|
||||
+
|
||||
+ The GNU C Library is free software; you can redistribute it and/or
|
||||
+ modify it under the terms of the GNU Lesser General Public
|
||||
+ License as published by the Free Software Foundation; either
|
||||
+ version 2.1 of the License, or (at your option) any later version.
|
||||
+
|
||||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ Lesser General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU Lesser General Public
|
||||
+ License along with the GNU C Library; if not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <stdint.h>
|
||||
+#include <pthread.h>
|
||||
+#include <unistd.h>
|
||||
+#include <getopt.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/xthread.h>
|
||||
+
|
||||
+static pthread_barrier_t barrier;
|
||||
+static pthread_mutex_t mutex;
|
||||
+static long long int iteration_count = 1000000;
|
||||
+static unsigned int thread_count = 3;
|
||||
+
|
||||
+static void *
|
||||
+thr_func (void *arg)
|
||||
+{
|
||||
+ long long int i;
|
||||
+ for (i = 0; i < iteration_count; i++)
|
||||
+ {
|
||||
+ if ((uintptr_t) arg == 0)
|
||||
+ {
|
||||
+ xpthread_mutex_destroy (&mutex);
|
||||
+ xpthread_mutex_init (&mutex, NULL);
|
||||
+ }
|
||||
+
|
||||
+ xpthread_barrier_wait (&barrier);
|
||||
+
|
||||
+ /* Test if enabling lock elision works if it is enabled concurrently.
|
||||
+ There was a race in FORCE_ELISION macro which leads to either
|
||||
+ pthread_mutex_destroy returning EBUSY as the owner was recorded
|
||||
+ by pthread_mutex_lock - in "normal mutex" code path - but was not
|
||||
+ resetted in pthread_mutex_unlock - in "elision" code path.
|
||||
+ Or it leads to the assertion in nptl/pthread_mutex_lock.c:
|
||||
+ assert (mutex->__data.__owner == 0);
|
||||
+ Please ensure that the test is run with lock elision:
|
||||
+ export GLIBC_TUNABLES=glibc.elision.enable=1 */
|
||||
+ xpthread_mutex_lock (&mutex);
|
||||
+ xpthread_mutex_unlock (&mutex);
|
||||
+
|
||||
+ xpthread_barrier_wait (&barrier);
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+ printf ("Starting %d threads to run %lld iterations.\n",
|
||||
+ thread_count, iteration_count);
|
||||
+
|
||||
+ pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t));
|
||||
+ xpthread_barrier_init (&barrier, NULL, thread_count);
|
||||
+ xpthread_mutex_init (&mutex, NULL);
|
||||
+
|
||||
+ for (i = 0; i < thread_count; i++)
|
||||
+ threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i);
|
||||
+
|
||||
+ for (i = 0; i < thread_count; i++)
|
||||
+ xpthread_join (threads[i]);
|
||||
+
|
||||
+ xpthread_barrier_destroy (&barrier);
|
||||
+ free (threads);
|
||||
+
|
||||
+ return EXIT_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+#define OPT_ITERATIONS 10000
|
||||
+#define OPT_THREADS 10001
|
||||
+#define CMDLINE_OPTIONS \
|
||||
+ { "iterations", required_argument, NULL, OPT_ITERATIONS }, \
|
||||
+ { "threads", required_argument, NULL, OPT_THREADS },
|
||||
+static void
|
||||
+cmdline_process (int c)
|
||||
+{
|
||||
+ long long int arg = strtoll (optarg, NULL, 0);
|
||||
+ switch (c)
|
||||
+ {
|
||||
+ case OPT_ITERATIONS:
|
||||
+ if (arg > 0)
|
||||
+ iteration_count = arg;
|
||||
+ break;
|
||||
+ case OPT_THREADS:
|
||||
+ if (arg > 0 && arg < 100)
|
||||
+ thread_count = arg;
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+#define CMDLINE_PROCESS cmdline_process
|
||||
+#define TIMEOUT 50
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h
|
||||
index 1e2092a05d5610f7..05c94e7a710c0eb9 100644
|
||||
--- a/sysdeps/nptl/bits/thread-shared-types.h
|
||||
+++ b/sysdeps/nptl/bits/thread-shared-types.h
|
||||
@@ -124,7 +124,27 @@ struct __pthread_mutex_s
|
||||
unsigned int __nusers;
|
||||
#endif
|
||||
/* KIND must stay at this position in the structure to maintain
|
||||
- binary compatibility with static initializers. */
|
||||
+ binary compatibility with static initializers.
|
||||
+
|
||||
+ Concurrency notes:
|
||||
+ The __kind of a mutex is initialized either by the static
|
||||
+ PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init.
|
||||
+
|
||||
+ After a mutex has been initialized, the __kind of a mutex is usually not
|
||||
+ changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can
|
||||
+ be enabled. This is done concurrently in the pthread_mutex_*lock functions
|
||||
+ by using the macro FORCE_ELISION. This macro is only defined for
|
||||
+ architectures which supports lock elision.
|
||||
+
|
||||
+ For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and
|
||||
+ PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set
|
||||
+ type of a mutex.
|
||||
+ Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set
|
||||
+ with pthread_mutexattr_settype.
|
||||
+ After a mutex has been initialized, the functions pthread_mutex_*lock can
|
||||
+ enable elision - if the mutex-type and the machine supports it - by setting
|
||||
+ the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards
|
||||
+ the lock / unlock functions are using specific elision code-paths. */
|
||||
int __kind;
|
||||
__PTHREAD_COMPAT_PADDING_MID
|
||||
#if __PTHREAD_MUTEX_NUSERS_AFTER_KIND
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h
|
||||
index fe5d6ceade2bad36..d8f5a4b1c7713bd4 100644
|
||||
--- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h
|
||||
@@ -18,9 +18,45 @@
|
||||
|
||||
/* Automatically enable elision for existing user lock kinds. */
|
||||
#define FORCE_ELISION(m, s) \
|
||||
- if (__pthread_force_elision \
|
||||
- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
|
||||
+ if (__pthread_force_elision) \
|
||||
{ \
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \
|
||||
- s; \
|
||||
+ /* See concurrency notes regarding __kind in \
|
||||
+ struct __pthread_mutex_s in \
|
||||
+ sysdeps/nptl/bits/thread-shared-types.h. \
|
||||
+ \
|
||||
+ There are the following cases for the kind of a mutex \
|
||||
+ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \
|
||||
+ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
|
||||
+ only one of both flags can be set): \
|
||||
+ - both flags are not set: \
|
||||
+ This is the first lock operation for this mutex. Enable \
|
||||
+ elision as it is not enabled so far. \
|
||||
+ Note: It can happen that multiple threads are calling e.g. \
|
||||
+ pthread_mutex_lock at the same time as the first lock \
|
||||
+ operation for this mutex. Then elision is enabled for this \
|
||||
+ mutex by multiple threads. Storing with relaxed MO is enough \
|
||||
+ as all threads will store the same new value for the kind of \
|
||||
+ the mutex. But we have to ensure that we always use the \
|
||||
+ elision path regardless if this thread has enabled elision or \
|
||||
+ another one. \
|
||||
+ \
|
||||
+ - PTHREAD_MUTEX_ELISION_NP flag is set: \
|
||||
+ Elision was already enabled for this mutex by a previous lock \
|
||||
+ operation. See case above. Just use the elision path. \
|
||||
+ \
|
||||
+ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \
|
||||
+ Elision was explicitly disabled by pthread_mutexattr_settype. \
|
||||
+ Do not use the elision path. \
|
||||
+ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \
|
||||
+ changed after mutex initialization. */ \
|
||||
+ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \
|
||||
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
|
||||
+ { \
|
||||
+ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \
|
||||
+ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \
|
||||
+ } \
|
||||
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \
|
||||
+ { \
|
||||
+ s; \
|
||||
+ } \
|
||||
}
|
||||
diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h
|
||||
index d8a1b9972f739cfe..71f32367dd6b6489 100644
|
||||
--- a/sysdeps/unix/sysv/linux/s390/force-elision.h
|
||||
+++ b/sysdeps/unix/sysv/linux/s390/force-elision.h
|
||||
@@ -18,9 +18,45 @@
|
||||
|
||||
/* Automatically enable elision for existing user lock kinds. */
|
||||
#define FORCE_ELISION(m, s) \
|
||||
- if (__pthread_force_elision \
|
||||
- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
|
||||
+ if (__pthread_force_elision) \
|
||||
{ \
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \
|
||||
- s; \
|
||||
+ /* See concurrency notes regarding __kind in \
|
||||
+ struct __pthread_mutex_s in \
|
||||
+ sysdeps/nptl/bits/thread-shared-types.h. \
|
||||
+ \
|
||||
+ There are the following cases for the kind of a mutex \
|
||||
+ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \
|
||||
+ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
|
||||
+ only one of both flags can be set): \
|
||||
+ - both flags are not set: \
|
||||
+ This is the first lock operation for this mutex. Enable \
|
||||
+ elision as it is not enabled so far. \
|
||||
+ Note: It can happen that multiple threads are calling e.g. \
|
||||
+ pthread_mutex_lock at the same time as the first lock \
|
||||
+ operation for this mutex. Then elision is enabled for this \
|
||||
+ mutex by multiple threads. Storing with relaxed MO is enough \
|
||||
+ as all threads will store the same new value for the kind of \
|
||||
+ the mutex. But we have to ensure that we always use the \
|
||||
+ elision path regardless if this thread has enabled elision or \
|
||||
+ another one. \
|
||||
+ \
|
||||
+ - PTHREAD_MUTEX_ELISION_NP flag is set: \
|
||||
+ Elision was already enabled for this mutex by a previous lock \
|
||||
+ operation. See case above. Just use the elision path. \
|
||||
+ \
|
||||
+ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \
|
||||
+ Elision was explicitly disabled by pthread_mutexattr_settype. \
|
||||
+ Do not use the elision path. \
|
||||
+ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \
|
||||
+ changed after mutex initialization. */ \
|
||||
+ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \
|
||||
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
|
||||
+ { \
|
||||
+ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \
|
||||
+ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \
|
||||
+ } \
|
||||
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \
|
||||
+ { \
|
||||
+ s; \
|
||||
+ } \
|
||||
}
|
||||
diff --git a/sysdeps/unix/sysv/linux/x86/force-elision.h b/sysdeps/unix/sysv/linux/x86/force-elision.h
|
||||
index dd659c908f3046c1..61282d6678d89787 100644
|
||||
--- a/sysdeps/unix/sysv/linux/x86/force-elision.h
|
||||
+++ b/sysdeps/unix/sysv/linux/x86/force-elision.h
|
||||
@@ -18,9 +18,45 @@
|
||||
|
||||
/* Automatically enable elision for existing user lock kinds. */
|
||||
#define FORCE_ELISION(m, s) \
|
||||
- if (__pthread_force_elision \
|
||||
- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
|
||||
+ if (__pthread_force_elision) \
|
||||
{ \
|
||||
- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \
|
||||
- s; \
|
||||
+ /* See concurrency notes regarding __kind in \
|
||||
+ struct __pthread_mutex_s in \
|
||||
+ sysdeps/nptl/bits/thread-shared-types.h. \
|
||||
+ \
|
||||
+ There are the following cases for the kind of a mutex \
|
||||
+ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \
|
||||
+ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
|
||||
+ only one of both flags can be set): \
|
||||
+ - both flags are not set: \
|
||||
+ This is the first lock operation for this mutex. Enable \
|
||||
+ elision as it is not enabled so far. \
|
||||
+ Note: It can happen that multiple threads are calling e.g. \
|
||||
+ pthread_mutex_lock at the same time as the first lock \
|
||||
+ operation for this mutex. Then elision is enabled for this \
|
||||
+ mutex by multiple threads. Storing with relaxed MO is enough \
|
||||
+ as all threads will store the same new value for the kind of \
|
||||
+ the mutex. But we have to ensure that we always use the \
|
||||
+ elision path regardless if this thread has enabled elision or \
|
||||
+ another one. \
|
||||
+ \
|
||||
+ - PTHREAD_MUTEX_ELISION_NP flag is set: \
|
||||
+ Elision was already enabled for this mutex by a previous lock \
|
||||
+ operation. See case above. Just use the elision path. \
|
||||
+ \
|
||||
+ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \
|
||||
+ Elision was explicitly disabled by pthread_mutexattr_settype. \
|
||||
+ Do not use the elision path. \
|
||||
+ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \
|
||||
+ changed after mutex initialization. */ \
|
||||
+ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \
|
||||
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
|
||||
+ { \
|
||||
+ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \
|
||||
+ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \
|
||||
+ } \
|
||||
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \
|
||||
+ { \
|
||||
+ s; \
|
||||
+ } \
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
commit bd3b0fbae33a9a4cc5e2daf049443d5cf03d4251
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Mon Nov 5 12:47:30 2018 +0100
|
||||
|
||||
libanl: properly cleanup if first helper thread creation failed (bug 22927)
|
||||
|
||||
diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c
|
||||
index e7c3b63cc5725b4f..80a2cff8353fcb6c 100644
|
||||
--- a/resolv/gai_misc.c
|
||||
+++ b/resolv/gai_misc.c
|
||||
@@ -261,8 +261,11 @@ __gai_enqueue_request (struct gaicb *gaicbp)
|
||||
/* We cannot create a thread in the moment and there is
|
||||
also no thread running. This is a problem. `errno' is
|
||||
set to EAGAIN if this is only a temporary problem. */
|
||||
- assert (lastp->next == newp);
|
||||
- lastp->next = NULL;
|
||||
+ assert (requests == newp || lastp->next == newp);
|
||||
+ if (lastp != NULL)
|
||||
+ lastp->next = NULL;
|
||||
+ else
|
||||
+ requests = NULL;
|
||||
requests_tail = lastp;
|
||||
|
||||
newp->next = freelist;
|
@ -0,0 +1,48 @@
|
||||
commit 17b26500f9bb926d85e86821d014f7c1bb88043c
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Aug 13 21:35:27 2018 +0000
|
||||
|
||||
Update syscall-names.list for Linux 4.18.
|
||||
|
||||
This patch updates sysdeps/unix/sysv/linux/syscall-names.list for
|
||||
Linux 4.18. The io_pgetevents and rseq syscalls are added to the
|
||||
kernel on various architectures, so need to be mentioned in this file.
|
||||
|
||||
Tested with build-many-glibcs.py.
|
||||
|
||||
* sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
|
||||
version to 4.18.
|
||||
(io_pgetevents): New syscall.
|
||||
(rseq): Likewise.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
|
||||
index 5306d538e6448163..9982a6334d46ae62 100644
|
||||
--- a/sysdeps/unix/sysv/linux/syscall-names.list
|
||||
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
|
||||
@@ -22,8 +22,8 @@
|
||||
# names are only used if the installed kernel headers also provide
|
||||
# them.
|
||||
|
||||
-# The list of system calls is current as of Linux 4.17.
|
||||
-kernel 4.17
|
||||
+# The list of system calls is current as of Linux 4.18.
|
||||
+kernel 4.18
|
||||
|
||||
FAST_atomic_update
|
||||
FAST_cmpxchg
|
||||
@@ -186,6 +186,7 @@ inotify_rm_watch
|
||||
io_cancel
|
||||
io_destroy
|
||||
io_getevents
|
||||
+io_pgetevents
|
||||
io_setup
|
||||
io_submit
|
||||
ioctl
|
||||
@@ -431,6 +432,7 @@ renameat2
|
||||
request_key
|
||||
restart_syscall
|
||||
rmdir
|
||||
+rseq
|
||||
rt_sigaction
|
||||
rt_sigpending
|
||||
rt_sigprocmask
|
@ -0,0 +1,30 @@
|
||||
commit 029ad711b8ad4cf0e5d98e0c138a35a23a376a74
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Oct 22 23:26:37 2018 +0000
|
||||
|
||||
Update kernel version in syscall-names.list to 4.19.
|
||||
|
||||
Linux 4.19 does not add any new syscalls (some existing ones are added
|
||||
to more architectures); this patch updates the version number in
|
||||
syscall-names.list to reflect that it's still current for 4.19.
|
||||
|
||||
Tested with build-many-glibcs.py.
|
||||
|
||||
* sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
|
||||
version to 4.19.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
|
||||
index 9982a6334d46ae62..f88001c9c38d5fc7 100644
|
||||
--- a/sysdeps/unix/sysv/linux/syscall-names.list
|
||||
+++ b/sysdeps/unix/sysv/linux/syscall-names.list
|
||||
@@ -22,8 +22,8 @@
|
||||
# names are only used if the installed kernel headers also provide
|
||||
# them.
|
||||
|
||||
-# The list of system calls is current as of Linux 4.18.
|
||||
-kernel 4.18
|
||||
+# The list of system calls is current as of Linux 4.19.
|
||||
+kernel 4.19
|
||||
|
||||
FAST_atomic_update
|
||||
FAST_cmpxchg
|
@ -0,0 +1,127 @@
|
||||
commit 745664bd798ec8fd50438605948eea594179fba1
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Aug 28 13:19:27 2018 +0200
|
||||
|
||||
nscd: Fix use-after-free in addgetnetgrentX [BZ #23520]
|
||||
|
||||
addinnetgrX may use the heap-allocated buffer, so free the buffer
|
||||
in this function.
|
||||
|
||||
diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c
|
||||
index 2b35389cc816c3c8..87059fb28042f0a5 100644
|
||||
--- a/nscd/netgroupcache.c
|
||||
+++ b/nscd/netgroupcache.c
|
||||
@@ -113,7 +113,8 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
|
||||
static time_t
|
||||
addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
const char *key, uid_t uid, struct hashentry *he,
|
||||
- struct datahead *dh, struct dataset **resultp)
|
||||
+ struct datahead *dh, struct dataset **resultp,
|
||||
+ void **tofreep)
|
||||
{
|
||||
if (__glibc_unlikely (debug_level > 0))
|
||||
{
|
||||
@@ -139,6 +140,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
size_t group_len = strlen (key) + 1;
|
||||
struct name_list *first_needed
|
||||
= alloca (sizeof (struct name_list) + group_len);
|
||||
+ *tofreep = NULL;
|
||||
|
||||
if (netgroup_database == NULL
|
||||
&& __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
|
||||
@@ -151,6 +153,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
|
||||
memset (&data, '\0', sizeof (data));
|
||||
buffer = xmalloc (buflen);
|
||||
+ *tofreep = buffer;
|
||||
first_needed->next = first_needed;
|
||||
memcpy (first_needed->name, key, group_len);
|
||||
data.needed_groups = first_needed;
|
||||
@@ -439,8 +442,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
}
|
||||
|
||||
out:
|
||||
- free (buffer);
|
||||
-
|
||||
*resultp = dataset;
|
||||
|
||||
return timeout;
|
||||
@@ -477,8 +478,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
group, group_len,
|
||||
db, uid);
|
||||
time_t timeout;
|
||||
+ void *tofree;
|
||||
if (result != NULL)
|
||||
- timeout = result->head.timeout;
|
||||
+ {
|
||||
+ timeout = result->head.timeout;
|
||||
+ tofree = NULL;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
request_header req_get =
|
||||
@@ -487,7 +492,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
.key_len = group_len
|
||||
};
|
||||
timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
|
||||
- &result);
|
||||
+ &result, &tofree);
|
||||
}
|
||||
|
||||
struct indataset
|
||||
@@ -560,7 +565,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
++dh->nreloads;
|
||||
if (cacheable)
|
||||
pthread_rwlock_unlock (&db->lock);
|
||||
- return timeout;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
if (he == NULL)
|
||||
@@ -596,17 +601,30 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
dh->usable = false;
|
||||
}
|
||||
|
||||
+ out:
|
||||
+ free (tofree);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
|
||||
+static time_t
|
||||
+addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
|
||||
+ const char *key, uid_t uid, struct hashentry *he,
|
||||
+ struct datahead *dh)
|
||||
+{
|
||||
+ struct dataset *ignore;
|
||||
+ void *tofree;
|
||||
+ time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
|
||||
+ &ignore, &tofree);
|
||||
+ free (tofree);
|
||||
+ return timeout;
|
||||
+}
|
||||
+
|
||||
void
|
||||
addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
|
||||
void *key, uid_t uid)
|
||||
{
|
||||
- struct dataset *ignore;
|
||||
-
|
||||
- addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
|
||||
+ addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -619,10 +637,8 @@ readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
|
||||
.type = GETNETGRENT,
|
||||
.key_len = he->len
|
||||
};
|
||||
- struct dataset *ignore;
|
||||
-
|
||||
- return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
|
||||
- &ignore);
|
||||
+ return addgetnetgrentX_ignore
|
||||
+ (db, -1, &req, db->data + he->key, he->owner, he, dh);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,234 @@
|
||||
commit a6e8926f8d49a213a9abb1a61f6af964f612ab7f
|
||||
Author: Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
Date: Fri Aug 31 18:04:32 2018 -0700
|
||||
|
||||
[BZ #20271] Add newlines in __libc_fatal calls.
|
||||
|
||||
diff --git a/grp/initgroups.c b/grp/initgroups.c
|
||||
index f056fbf5aa6aa14c..93e7f5814da6286d 100644
|
||||
--- a/grp/initgroups.c
|
||||
+++ b/grp/initgroups.c
|
||||
@@ -128,7 +128,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
|
||||
|
||||
/* This is really only for debugging. */
|
||||
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
|
||||
- __libc_fatal ("illegal status in internal_getgrouplist");
|
||||
+ __libc_fatal ("Illegal status in internal_getgrouplist.\n");
|
||||
|
||||
/* For compatibility reason we will continue to look for more
|
||||
entries using the next service even though data has already
|
||||
diff --git a/include/stdio.h b/include/stdio.h
|
||||
index 9162d4e24717e31a..7a5c09089fc4d348 100644
|
||||
--- a/include/stdio.h
|
||||
+++ b/include/stdio.h
|
||||
@@ -98,7 +98,8 @@ enum __libc_message_action
|
||||
do_backtrace = 1 << 1 /* Backtrace. */
|
||||
};
|
||||
|
||||
-/* Print out MESSAGE on the error output and abort. */
|
||||
+/* Print out MESSAGE (which should end with a newline) on the error output
|
||||
+ and abort. */
|
||||
extern void __libc_fatal (const char *__message)
|
||||
__attribute__ ((__noreturn__));
|
||||
extern void __libc_message (enum __libc_message_action action,
|
||||
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
|
||||
index 3e1105418210288e..ebf07ca82d87de7d 100644
|
||||
--- a/nptl/pthread_cond_wait.c
|
||||
+++ b/nptl/pthread_cond_wait.c
|
||||
@@ -516,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec rt;
|
||||
if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0)
|
||||
__libc_fatal ("clock_gettime does not support "
|
||||
- "CLOCK_MONOTONIC");
|
||||
+ "CLOCK_MONOTONIC\n");
|
||||
/* Convert the absolute timeout value to a relative
|
||||
timeout. */
|
||||
rt.tv_sec = abstime->tv_sec - rt.tv_sec;
|
||||
diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c
|
||||
index 2c74951f579f4afd..4764f14a45f68e0a 100644
|
||||
--- a/nscd/initgrcache.c
|
||||
+++ b/nscd/initgrcache.c
|
||||
@@ -159,7 +159,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req,
|
||||
|
||||
/* This is really only for debugging. */
|
||||
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
|
||||
- __libc_fatal ("illegal status in internal_getgrouplist");
|
||||
+ __libc_fatal ("Illegal status in internal_getgrouplist.\n");
|
||||
|
||||
any_success |= status == NSS_STATUS_SUCCESS;
|
||||
|
||||
diff --git a/nss/nsswitch.c b/nss/nsswitch.c
|
||||
index ee46f24424bc1ca2..3c48b4b85e881cdb 100644
|
||||
--- a/nss/nsswitch.c
|
||||
+++ b/nss/nsswitch.c
|
||||
@@ -235,7 +235,7 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name,
|
||||
/* This is really only for debugging. */
|
||||
if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
|
||||
|| status > NSS_STATUS_RETURN, 0))
|
||||
- __libc_fatal ("illegal status in __nss_next");
|
||||
+ __libc_fatal ("Illegal status in __nss_next.\n");
|
||||
|
||||
if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
|
||||
return 1;
|
||||
diff --git a/sysdeps/aarch64/dl-irel.h b/sysdeps/aarch64/dl-irel.h
|
||||
index 5889ee187b7a1eaf..bef71ed0f31a6387 100644
|
||||
--- a/sysdeps/aarch64/dl-irel.h
|
||||
+++ b/sysdeps/aarch64/dl-irel.h
|
||||
@@ -47,7 +47,7 @@ elf_irela (const ElfW(Rela) *reloc)
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
diff --git a/sysdeps/arm/dl-irel.h b/sysdeps/arm/dl-irel.h
|
||||
index a7b6456075659baf..be6eb7743eb5f08d 100644
|
||||
--- a/sysdeps/arm/dl-irel.h
|
||||
+++ b/sysdeps/arm/dl-irel.h
|
||||
@@ -46,7 +46,7 @@ elf_irel (const Elf32_Rel *reloc)
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/generic/unwind-dw2.c b/sysdeps/generic/unwind-dw2.c
|
||||
index 082609b34a3f773b..724c16a7f0bf465b 100644
|
||||
--- a/sysdeps/generic/unwind-dw2.c
|
||||
+++ b/sysdeps/generic/unwind-dw2.c
|
||||
@@ -843,7 +843,7 @@ execute_cfa_program (const unsigned char *insn_ptr,
|
||||
struct frame_state_reg_info *old_rs = fs->regs.prev;
|
||||
#ifdef _LIBC
|
||||
if (old_rs == NULL)
|
||||
- __libc_fatal ("invalid DWARF unwind data");
|
||||
+ __libc_fatal ("Invalid DWARF unwind data.\n");
|
||||
else
|
||||
#endif
|
||||
{
|
||||
diff --git a/sysdeps/i386/dl-irel.h b/sysdeps/i386/dl-irel.h
|
||||
index 55303180c7aca495..bcaf0668acf8e2f2 100644
|
||||
--- a/sysdeps/i386/dl-irel.h
|
||||
+++ b/sysdeps/i386/dl-irel.h
|
||||
@@ -45,7 +45,7 @@ elf_irel (const Elf32_Rel *reloc)
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
|
||||
index 1a5624789d4ab117..6fd27f0df6c27b69 100644
|
||||
--- a/sysdeps/nptl/futex-internal.h
|
||||
+++ b/sysdeps/nptl/futex-internal.h
|
||||
@@ -197,7 +197,7 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private);
|
||||
static __always_inline __attribute__ ((__noreturn__)) void
|
||||
futex_fatal_error (void)
|
||||
{
|
||||
- __libc_fatal ("The futex facility returned an unexpected error code.");
|
||||
+ __libc_fatal ("The futex facility returned an unexpected error code.\n");
|
||||
}
|
||||
|
||||
#endif /* futex-internal.h */
|
||||
diff --git a/sysdeps/powerpc/powerpc32/dl-irel.h b/sysdeps/powerpc/powerpc32/dl-irel.h
|
||||
index a7368b25829618cb..61d0e4cf61ec45d3 100644
|
||||
--- a/sysdeps/powerpc/powerpc32/dl-irel.h
|
||||
+++ b/sysdeps/powerpc/powerpc32/dl-irel.h
|
||||
@@ -46,7 +46,7 @@ elf_irela (const Elf32_Rela *reloc)
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/powerpc/powerpc64/dl-irel.h b/sysdeps/powerpc/powerpc64/dl-irel.h
|
||||
index ab13c04358868270..2fd0ee8a86e85ba0 100644
|
||||
--- a/sysdeps/powerpc/powerpc64/dl-irel.h
|
||||
+++ b/sysdeps/powerpc/powerpc64/dl-irel.h
|
||||
@@ -57,7 +57,7 @@ elf_irela (const Elf64_Rela *reloc)
|
||||
#endif
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/s390/dl-irel.h b/sysdeps/s390/dl-irel.h
|
||||
index d8ba7ba42709f45c..ecb24f0a9be0daa7 100644
|
||||
--- a/sysdeps/s390/dl-irel.h
|
||||
+++ b/sysdeps/s390/dl-irel.h
|
||||
@@ -46,7 +46,7 @@ elf_irela (const ElfW(Rela) *reloc)
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/sparc/sparc32/dl-irel.h b/sysdeps/sparc/sparc32/dl-irel.h
|
||||
index ffca36864f24d1fb..cf47cda8345b1a39 100644
|
||||
--- a/sysdeps/sparc/sparc32/dl-irel.h
|
||||
+++ b/sysdeps/sparc/sparc32/dl-irel.h
|
||||
@@ -56,7 +56,7 @@ elf_irela (const Elf32_Rela *reloc)
|
||||
else if (r_type == R_SPARC_NONE)
|
||||
;
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/sparc/sparc64/dl-irel.h b/sysdeps/sparc/sparc64/dl-irel.h
|
||||
index c5cd3057aca1baf6..446fed18365cfd13 100644
|
||||
--- a/sysdeps/sparc/sparc64/dl-irel.h
|
||||
+++ b/sysdeps/sparc/sparc64/dl-irel.h
|
||||
@@ -59,7 +59,7 @@ elf_irela (const Elf64_Rela *reloc)
|
||||
else if (r_type == R_SPARC_NONE)
|
||||
;
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
||||
diff --git a/sysdeps/unix/sysv/linux/netlink_assert_response.c b/sysdeps/unix/sysv/linux/netlink_assert_response.c
|
||||
index f31ccb52ffa56436..6afc3a17ced18e1c 100644
|
||||
--- a/sysdeps/unix/sysv/linux/netlink_assert_response.c
|
||||
+++ b/sysdeps/unix/sysv/linux/netlink_assert_response.c
|
||||
@@ -72,12 +72,12 @@ __netlink_assert_response (int fd, ssize_t result)
|
||||
char message[200];
|
||||
if (family < 0)
|
||||
__snprintf (message, sizeof (message),
|
||||
- "Unexpected error %d on netlink descriptor %d",
|
||||
+ "Unexpected error %d on netlink descriptor %d.\n",
|
||||
error_code, fd);
|
||||
else
|
||||
__snprintf (message, sizeof (message),
|
||||
"Unexpected error %d on netlink descriptor %d"
|
||||
- " (address family %d)",
|
||||
+ " (address family %d).\n",
|
||||
error_code, fd, family);
|
||||
__libc_fatal (message);
|
||||
}
|
||||
diff --git a/sysdeps/x86_64/dl-irel.h b/sysdeps/x86_64/dl-irel.h
|
||||
index 6ecc50fb42333c19..33f100d8b1781ea7 100644
|
||||
--- a/sysdeps/x86_64/dl-irel.h
|
||||
+++ b/sysdeps/x86_64/dl-irel.h
|
||||
@@ -45,7 +45,7 @@ elf_irela (const ElfW(Rela) *reloc)
|
||||
*reloc_addr = value;
|
||||
}
|
||||
else
|
||||
- __libc_fatal ("unexpected reloc type in static binary");
|
||||
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif /* dl-irel.h */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue