Perl_check_hash_fields_and_hekify - hekifying NVs is not locale-safe#24252
Perl_check_hash_fields_and_hekify - hekifying NVs is not locale-safe#24252richardleach wants to merge 1 commit intoPerl:bleadfrom
Conversation
|
Note: I'll try to add a test. |
|
Hmm, |
|
No, it does actually seem fine. |
|
I'm trying to understand the motivation behind this. No matter what the locale, a dot is supposed to be accepted as the decimal radix character., in addition to whatever the locale's official character is. We shouldn't be outputting a dot but we should always accept them. Is there a real life example where this didn't happen? |
|
This PR followed from the discussion here: #24228 (comment) |
The problem is the other direction, in This is a problem under (we use This is more obviously a bug if we also add runtime evaluation: Note the problem isn't locales, it's that we convert to a string too early. |
| && SvTYPE(sv) < SVt_PVMG | ||
| && SvOK(sv) | ||
| && !SvROK(sv) | ||
| && !SvNOK(sv) /* Decimal separator depends on runtime locale */ |
There was a problem hiding this comment.
It should be safe to do the NV to string conversion if IN_LC_COMPILETIME(LC_NUMERIC) is false, so maybe:
&& !(SvNOK(sv) && IN_LC_COMPILETIME(LC_NUMERIC))
which I think is more readable than:
&& (!SvNOK(sv) || !IN_LC_COMPILETIME(LC_NUMERIC))
There was a problem hiding this comment.
The IN_LC_COMPILETIME() check should be cheap in the non-use locale; common case.
There was a problem hiding this comment.
How does IN_LC_COMPILETIME work? Is it safe against things like hekification within BEGIN {} blocks before the use locale; is encountered, or require locale; (if that's allowed) at runtime?
There was a problem hiding this comment.
Hmm, I've added a couple of tests into t/run/locale.t and the one relevant to this PR fails if the !SvNOK(sv) test is changed to !(SvNOK(sv) && IN_LC_COMPILETIME(LC_NUMERIC)). Not sure if that's just the way the tests have been written though....
There was a problem hiding this comment.
I hadn't looked, but it looks like the run time vs compile time distinction in the macros is broken (or unneeded).
During compilation, while generating OPs, PL_curcop points at PL_compiling, and during peep-time (still compiling) PL_curcop points at the most recent COP, so it's always correct to check PL_curcop.
Functions like Perl_ckwarn_common() which can be called at compiler or run time only check PL_curcop.
So this should be checking IN_LC_RUNTIME(LC_NUMERIC) and the new tests pass if I change it:
diff --git a/op.c b/op.c
index c36327cf67..5974518ab5 100644
--- a/op.c
+++ b/op.c
@@ -2806,7 +2806,7 @@ Perl_check_hash_fields_and_hekify(pTHX_ UNOP *rop, SVOP *key_op, int real)
&& SvTYPE(sv) < SVt_PVMG
&& SvOK(sv)
&& !SvROK(sv)
- && !SvNOK(sv) /* Decimal separator depends on runtime locale */
+ && !(SvNOK(sv) && IN_LC_RUNTIME(LC_NUMERIC)) /* Decimal separator depends on runtime locale */
&& real)
{
SSize_t keylen;
`Perl_check_hash_fields_and_hekify` used to convert IV, NV, and PV `OP_CONST` SV values into shared HEKs at compile time. However, the decimal separator character is locale dependent, so it is unsafe to perform a one-off conversion of an NV to a hash key using the compile time locale. This commit adds a check at optimization time to ensure that NVs are not unsafely hekified. It also adds a couple of new regression tests.
60f6b05 to
3a2eb9a
Compare
Perl_check_hash_fields_and_hekifyused to convert IV, NV, and PVOP_CONSTSV values into shared HEKs at compile time. However, the decimal separator character is locale dependent, so it is unsafe to perform a one-off conversion of an NV to a hash key using the compile time locale.This commit adds a check to ensure that NVs are no longer hekified.