Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0927ade

Browse files
jimctonycoz
authored andcommittedMay 17, 2016
better glibc i_modulo bug handling
pp-i-modulo code currently detects a glibc bug at runtime, at the 1st exec of each I_MODULO op. This is suboptimal; the bug should be detectable early, and PL_ppaddr[I_MODULO] updated just once, before any optrees are built. Then, because we avoid the need to fixup I_MODULO ops in already built optrees, we can drop the !PERL_DEBUG_READONLY_OPS limitation on the alternative/workaround I_MODULO implementation that avoids the bug. perl.c: bug detection code is copied from PP(i_modulo), into S_fixup_platform_bugs(), and called from perl_construct(). It patches Perl_pp_i_modulo_1() into PL_ppaddr[I_MODULO] when needed. pp.c: PP(i_modulo_0), the original implementation, is renamed to PP(i_modulo) PP(i_modulo_1), the bug-fix workaround, is renamed _glibc_bugfix it is #ifdefd as before, but dropping !PERL_DEBUG_READONLY_OPS PP(i_modulo) - the 1st-exec switcher code, is dropped ocode.pl: Two i_modulo entries are added to @raw_alias. - 1st alias: Perl_pp_i_modulo => 'i_modulo' - 2nd alt: Perl_pp_i_modulo_glibc_bugfix => 'i_modulo' 1st is a restatement of the default alias/mapping that would be created without the line. 2nd line is then seen as alternative to the explicit mapping set by 1st. Alternative functions are written to pp_proto.h after the standard Perl_pp_* list, and include #if-cond, #endif wrappings, as was specified by 2nd @raw_alias addition. Changes tested by inserting '1 ||' into the 3 ifdefs and bug-detection code. TODO: In pp_proto.h generation, the #ifdef wrapping code which handles the alternative functions looks like it should also be used for the non-alternate functions. In particular, there are a handful of pp-function prototypes that should be wrapped with #ifdef HAS_SOCKET. That said, there have been no problem reports, so I left it alone. TonyC: make S_fixup_platform_bugs static, porting/libperl.t was failing.
1 parent 38c8d7b commit 0927ade

File tree

4 files changed

+50
-56
lines changed

4 files changed

+50
-56
lines changed
 

‎perl.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,26 @@ Initializes a new Perl interpreter. See L<perlembed>.
214214
=cut
215215
*/
216216

217+
static void
218+
S_fixup_platform_bugs(void)
219+
{
220+
#if defined(__GLIBC__) && IVSIZE == 8 \
221+
&& ( __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8))
222+
{
223+
IV l = 3;
224+
IV r = -10;
225+
/* Cannot do this check with inlined IV constants since
226+
* that seems to work correctly even with the buggy glibc. */
227+
if (l % r == -3) {
228+
dTHX;
229+
/* Yikes, we have the bug.
230+
* Patch in the workaround version. */
231+
PL_ppaddr[OP_I_MODULO] = &Perl_pp_i_modulo_glibc_bugfix;
232+
}
233+
}
234+
#endif
235+
}
236+
217237
void
218238
perl_construct(pTHXx)
219239
{
@@ -251,6 +271,8 @@ perl_construct(pTHXx)
251271

252272
init_ids();
253273

274+
S_fixup_platform_bugs();
275+
254276
JMPENV_BOOTSTRAP;
255277
STATUS_ALL_SUCCESS;
256278

‎pp.c

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2785,13 +2785,7 @@ PP(pp_i_divide)
27852785
}
27862786
}
27872787

2788-
#if defined(__GLIBC__) && IVSIZE == 8 && !defined(PERL_DEBUG_READONLY_OPS) \
2789-
&& ( __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8))
2790-
STATIC
2791-
PP(pp_i_modulo_0)
2792-
#else
27932788
PP(pp_i_modulo)
2794-
#endif
27952789
{
27962790
/* This is the vanilla old i_modulo. */
27972791
dSP; dATARGET;
@@ -2809,11 +2803,10 @@ PP(pp_i_modulo)
28092803
}
28102804
}
28112805

2812-
#if defined(__GLIBC__) && IVSIZE == 8 && !defined(PERL_DEBUG_READONLY_OPS) \
2806+
#if defined(__GLIBC__) && IVSIZE == 8 \
28132807
&& ( __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8))
2814-
STATIC
2815-
PP(pp_i_modulo_1)
28162808

2809+
PP(pp_i_modulo_glibc_bugfix)
28172810
{
28182811
/* This is the i_modulo with the workaround for the _moddi3 bug
28192812
* in (at least) glibc 2.2.5 (the PERL_ABS() the workaround).
@@ -2832,49 +2825,6 @@ PP(pp_i_modulo_1)
28322825
RETURN;
28332826
}
28342827
}
2835-
2836-
PP(pp_i_modulo)
2837-
{
2838-
dVAR; dSP; dATARGET;
2839-
tryAMAGICbin_MG(modulo_amg, AMGf_assign);
2840-
{
2841-
dPOPTOPiirl_nomg;
2842-
if (!right)
2843-
DIE(aTHX_ "Illegal modulus zero");
2844-
/* The assumption is to use hereafter the old vanilla version... */
2845-
PL_op->op_ppaddr =
2846-
PL_ppaddr[OP_I_MODULO] =
2847-
Perl_pp_i_modulo_0;
2848-
/* .. but if we have glibc, we might have a buggy _moddi3
2849-
* (at least glibc 2.2.5 is known to have this bug), in other
2850-
* words our integer modulus with negative quad as the second
2851-
* argument might be broken. Test for this and re-patch the
2852-
* opcode dispatch table if that is the case, remembering to
2853-
* also apply the workaround so that this first round works
2854-
* right, too. See [perl #9402] for more information. */
2855-
{
2856-
IV l = 3;
2857-
IV r = -10;
2858-
/* Cannot do this check with inlined IV constants since
2859-
* that seems to work correctly even with the buggy glibc. */
2860-
if (l % r == -3) {
2861-
/* Yikes, we have the bug.
2862-
* Patch in the workaround version. */
2863-
PL_op->op_ppaddr =
2864-
PL_ppaddr[OP_I_MODULO] =
2865-
&Perl_pp_i_modulo_1;
2866-
/* Make certain we work right this time, too. */
2867-
right = PERL_ABS(right);
2868-
}
2869-
}
2870-
/* avoid FPE_INTOVF on some platforms when left is IV_MIN */
2871-
if (right == -1)
2872-
SETi( 0 );
2873-
else
2874-
SETi( left % right );
2875-
RETURN;
2876-
}
2877-
}
28782828
#endif
28792829

28802830
PP(pp_i_add)

‎pp_proto.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,4 +293,9 @@ PERL_CALLCONV OP *Perl_pp_warn(pTHX);
293293
PERL_CALLCONV OP *Perl_pp_xor(pTHX);
294294
PERL_CALLCONV OP *Perl_unimplemented_op(pTHX);
295295

296+
/* alternative functions */
297+
#if defined(__GLIBC__) && IVSIZE == 8 && ( __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8))
298+
PERL_CALLCONV OP *Perl_pp_i_modulo_glibc_bugfix(pTHX);
299+
#endif
300+
296301
/* ex: set ro: */

‎regen/opcode.pl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ BEGIN
7171
$args{$key} = $args;
7272
}
7373

74-
# Set up aliases
74+
# Set up aliases, and alternative funcs
7575

76-
my %alias;
76+
my (%alias, %alts);
7777

7878
# Format is "this function" => "does these op names"
7979
my @raw_alias = (
@@ -139,16 +139,25 @@ BEGIN
139139
Perl_pp_shostent => [qw(snetent sprotoent sservent)],
140140
Perl_pp_aelemfast => ['aelemfast_lex'],
141141
Perl_pp_grepstart => ['mapstart'],
142+
143+
# 2 i_modulo mappings: 2nd is alt, needs 1st (explicit default) to not override the default
144+
Perl_pp_i_modulo => ['i_modulo'],
145+
Perl_pp_i_modulo_glibc_bugfix => {
146+
'i_modulo' =>
147+
'#if defined(__GLIBC__) && IVSIZE == 8 '.
148+
' && ( __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8))' },
142149
);
143150

144151
while (my ($func, $names) = splice @raw_alias, 0, 2) {
145152
if (ref $names eq 'ARRAY') {
146153
foreach (@$names) {
147-
$alias{$_} = [$func, ''];
154+
defined $alias{$_}
155+
? $alts{$_} : $alias{$_} = [$func, ''];
148156
}
149157
} else {
150158
while (my ($opname, $cond) = each %$names) {
151-
$alias{$opname} = [$func, $cond];
159+
defined $alias{$opname}
160+
? $alts{$opname} : $alias{$opname} = [$func, $cond];
152161
}
153162
}
154163
}
@@ -1251,6 +1260,14 @@ sub gen_op_is_macro {
12511260
++$funcs{$name};
12521261
}
12531262
print $pp "PERL_CALLCONV OP *$_(pTHX);\n" foreach sort keys %funcs;
1263+
1264+
print $pp "\n/* alternative functions */\n" if keys %alts;
1265+
for my $fn (sort keys %alts) {
1266+
my ($x, $cond) = @{$alts{$fn}};
1267+
print $pp "$cond\n" if $cond;
1268+
print $pp "PERL_CALLCONV OP *$x(pTHX);\n";
1269+
print $pp "#endif\n" if $cond;
1270+
}
12541271
}
12551272

12561273
print $oc "\n\n";

0 commit comments

Comments
 (0)
Please sign in to comment.