tinycc-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Tinycc-devel] Fixed an issue with switch/case statements on unsigne


From: Alexander Strasser
Subject: Re: [Tinycc-devel] Fixed an issue with switch/case statements on unsigned 64 bits
Date: Wed, 19 Aug 2020 20:42:00 +0200
User-agent: Mutt/1.9.4 (2018-02-28)

Hi Christian,

did you put Willy in Cc?

If yes, sorry for the noise.


Best regards,
  Alexander


On 2020-08-18 18:45 +0200, Christian JULLIEN wrote:
> Recent change has an issue with some tests
>
> macOS x64 and Linux ARM------------ test3 ------------tcctest.c:1939: error: 
> duplicate case valuemake[2]: *** [test3] Error 1------------ memtest 
> ------------../tests/tcctest.c:1939: error: duplicate case valuemake[2]: *** 
> [memtest] Error 1
> Linux Aarch64:../arm64-gen.c:1382: error: duplicate case valuemake[2]: *** 
> [Makefile:107: libtest_mt] Error 1------------ test3 ------------In file 
> included from ../tcc.c:23:In file included from 
> ../libtcc.c:35:../arm64-gen.c:1382: error: duplicate case valuemake[2]: *** 
> [Makefile:139: test3] Error 1------------ memtest ------------
>
>
>  Le : 18 août 2020 à 15:40 (GMT +02:00)
> De : "Willy Tarreau" <w@1wt.eu>
> À : "tinycc-devel@nongnu.org" <tinycc-devel@nongnu.org>
> Objet : [Tinycc-devel] Fixed an issue with switch/case statements on
>  unsigned 64 bits
>
>
> Hello,
>
> I managed to build all of haproxy using the latest tcc by applying very
> minor cosmetic changes that I'm going to commit. However I faced an issue
> that was really a bug. We have a function that's used to count digits for
> unsigned long long integers (well, unsigned long on 64-bit). And I was
> getting a warning that one statement was empty, and I could verify that
> the corresponding code was not matched. I simplified it to this test case:
>
>   #include <limits.h>
>   #include <stdio.h>
>   #include <stdlib.h>
>
>   int nbdg(unsigned long n)
>   {
>   switch (n) {
>   case                    1UL ...                   9UL: return 1;
>   case                   10UL ...                  99UL: return 2;
>   case                  100UL ...                 999UL: return 3;
>   case                 1000UL ...                9999UL: return 4;
>   case                10000UL ...               99999UL: return 5;
>   case               100000UL ...              999999UL: return 6;
>   case              1000000UL ...             9999999UL: return 7;
>   case             10000000UL ...            99999999UL: return 8;
>   case            100000000UL ...           999999999UL: return 9;
>   case           1000000000UL ...          9999999999UL: return 10;
>   case          10000000000UL ...         99999999999UL: return 11;
>   case         100000000000UL ...        999999999999UL: return 12;
>   case        1000000000000UL ...       9999999999999UL: return 13;
>   case       10000000000000UL ...      99999999999999UL: return 14;
>   case      100000000000000UL ...     999999999999999UL: return 15;
>   case     1000000000000000UL ...    9999999999999999UL: return 16;
>   case    10000000000000000UL ...   99999999999999999UL: return 17;
>   case   100000000000000000UL ...  999999999999999999UL: return 18;
>   case  1000000000000000000UL ... 9999999999999999999UL: return 19;
>   case 10000000000000000000UL ...             ULONG_MAX: return 20;
>   }
>   return 0;
>   }
>
>   int main(int argc, char **argv)
>   {
>   unsigned long v = strtoul(argc > 1 ? argv[1] : "1111", NULL, 0);
>   printf("%lu : %d\n", v, nbdg(v));
>   return 0;
>   }
>
> When executed you get this:
>
>   $ x="";for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0; do x=$x$i; ./a.out 
> $x;done
>   1 : 1
>   12 : 2
>   123 : 3
>   1234 : 4
>   12345 : 5
>   123456 : 6
>   1234567 : 7
>   12345678 : 8
>   123456789 : 9
>   1234567890 : 10
>   12345678901 : 11
>   123456789012 : 12
>   1234567890123 : 13
>   12345678901234 : 14
>   123456789012345 : 15
>   1234567890123456 : 16
>   12345678901234567 : 17
>   123456789012345678 : 18
>   1234567890123456789 : 0     <----- note this one
>   12345678901234567890 : 20
>
> The reason is a sign change between the bounds in the range below :
>
>     case  1000000000000000000UL ... 9999999999999999999UL: return 19;
>
>   $ printf "%016x\n" 1000000000000000000
>   0de0b6b3a7640000
>   $ printf "%016x\n" 9999999999999999999
>   8ac7230489e7ffff
>
> And there were actually two issues resulting from this:
>   - the qsort performed on integer values was no correct since it would
>     always be performed on signed integers ;
>   - the emitted code would still use signed comparisons (jg/jle) instead
>     of unsigned ones (ja/jbe).
>
> So I could fix by taking care of using two distinct case_cmp functions
> depending on the sign of the expression, and emitting the warning
> appropriately.
>
> While looking for how to submit the fix back, I applied the procedure
> described on https://repo.or.cz/w/tinycc.git expecting my patch would
> possibly land into a queue or that I would be asked to register or
> anything, but I was surprised to see it merged (commit b107f7bdd). I
> hope I didn't do any mistake, otherwise please let me know.
>
> Last, I'm not subscribed to the list (too many lists already on my side)
> so please keep me in CC for any replies.
>
> Oh by the way, when working on porting haproxy, I discovered a nasty
> issue in glibc that #defines __attribute__() to empty when not on GCC.
> The nasty effect is that constructors are silently ignored and not called.
> I found a workaround that I'm going to apply to haproxy, which consists
> in undefining __attribute__() and redefining it to itself so that if it's
> redefined we get an error. It solved my problem, but I thought that others
> might want to be aware of this.
>
> Thanks!
> Willy



reply via email to

[Prev in Thread] Current Thread [Next in Thread]