[pve-devel] [PATCH v3 many 00/66] fix #4156: introduce new notification system

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Jul 19 11:54:25 CEST 2023


On Wed, Jul 19, 2023 at 10:40:09AM +0200, Lukas Wagner wrote:
> Hi again,
> 
> On 7/18/23 14:34, Dominik Csapak wrote:
> > * i found one bug, but not quite sure yet where it comes from exactly,
> >    putting in emojis into a field (e.g. a comment or author) it's accepted,
> >    but editing a different entry fails with:
> > 
> > --->8---
> > could not serialize configuration: writing 'notifications.cfg' failed: detected unexpected control character in section 'testgroup' key 'comment' (500)
> > ---8<---
> > 
> > not sure where the utf-8 info gets lost. (or we could limit all fields to ascii?)
> > such a notification target still works AFAICT (but if set as e.g. the author it's
> > probably the wrong value)
> > 
> > (i used 😀 as a test)
> 
> So I investigated a bit and found a minimal reproducer. Turns out it's an encoding issue
> in the FFI interface (perl->rust).
> 
> Let's assume that we have the following exported function in the pve-rs bindings:
> 
>   #[export]
>   fn test_emoji(name: &str) {
>       dbg!(&name);
>   }
> 
> 
> 
>   use PVE::RS::Notify;
>   my $str = "😊";

Without `use utf8;`, this produces a "byte string":

    $ perl -MDevel::Peek -e 'my $str = "😊"; Dump($str);'
    SV = PV(0x5576f4e0cea0) at 0x5576f4e39370
      REFCNT = 1
      FLAGS = (POK,IsCOW,pPOK)
      PV = 0x5576f4e424d0 "\xF0\x9F\x98\x8A"\0
      CUR = 4
      LEN = 10
      COW_REFCNT = 1

Note that \xF0\x9F\x98\x8A.

>   PVE::RS::Notify::test_emoji($str);
> 
> 
>   root at pve:~# perl test.pl
>   [src/notify.rs:562] &name = "ð\u{9f}\u{98}\u{8a}"

Note the `\u` portions here. This string contains
the *UTF-8* characters 0xF0, 0x9F, 0x98, 0x8A.

And how is it supposed to know any better.

> 
> To me it looks a bit like a UTF-16/UTF-8 mixup:
> 
> ð = 0x00F0 in UTF16
> 😊 = 0xF0 0x9F 0x98 0x8A in UTF-8
> 
> The issue can be fixed by doing a `$str = encode('utf-8', $str);` before calling
> `test_emoji`.

Perl and most of our perl code never cared (hence we already ran into a
bunch of utf-8 issues and for a long time did the whole "transport
encoding vs actual encoding" in HTTP vs JS vs json vs perl strings
completely *wrong* (and probably still do)), and a lot of *files* aren't
even *defined* to have a specific encoding (eg. interpreting bytes >0x80
from `/etc/network/interfaces` as utf-8 may simply be the *wrong* thing
to do).

Sure, the perlmod layer could be an issue. But I wouldn't jump to
conclusions there.

Also, note what *actually* happens if you `encode('utf-8', $str)`:

    $ perl -MEncode -MDevel::Peek -e 'my $a = encode("utf-8", "👍"); Dump($a);'
    SV = PV(0x55f62dfe6170) at 0x55f62e012430
      REFCNT = 1
      FLAGS = (POK,IsCOW,pPOK)
      PV = 0x55f62e1cbe60 "\xC3\xB0\xC2\x9F\xC2\x91\xC2\x8D"\0
      CUR = 8
      LEN = 10
      COW_REFCNT = 0

Now you have the UTF-8 encoding of each character in there explicitly.

What you really want would be for perl to acknowledge that you already
have utf-8:

    $ perl -MDevel::Peek -e 'use utf8; my $a = "👍"; Dump($a);'
    SV = PV(0x56265764cea0) at 0x5626576793e8
      REFCNT = 1
      FLAGS = (POK,IsCOW,pPOK,UTF8)
      PV = 0x5626576a2b60 "\xF0\x9F\x91\x8D"\0 [UTF8 "\x{1f44d}"]
      CUR = 4
      LEN = 10
      COW_REFCNT = 1

But we don't use `use utf8;` in our code base because it has too many
side effects.

To mark an utf-8 encoded not-as-utf-8-marked string as utf-8 in perl,
you can *decode* it:

    $ perl -MDevel::Peek -e 'use utf8; no utf8; my $a = "👍"; utf8::decode($a); Dump($a);'
    SV = PV(0x55a5c9c45ea0) at 0x55a5c9c723a8
      REFCNT = 1
      FLAGS = (POK,pPOK,UTF8)
      PV = 0x55a5c9c64280 "\xF0\x9F\x91\x8D"\0 [UTF8 "\x{1f44d}"]
      CUR = 4
      LEN = 10

All that said, I have not yet looked at the perl side (or perlmod side)
and cannot say what's going on.

But If you hand utf-8 *bytes* which aren't marked as utf-8 to perlmod,
it'll do what perl does and just encode each byte as utf-8.

*Guessing* that it's utf-8 would surely work - *this time* - but might
simply be *wrong* other times.





More information about the pve-devel mailing list