Debian Bug report logs - #1086791
gcc: riscv64 backend emits large relocations due to loop strength reduction

Package: gcc-14; Maintainer for gcc-14 is Debian GCC Maintainers <[email protected]>; Source for gcc-14 is src:gcc-14 (PTS, buildd, popcon).

Affects: lziprecover

Reported by: Aurelien Jarno <[email protected]>

Date: Tue, 5 Nov 2024 21:30:01 UTC

Severity: important

Tags: ftbfs, upstream

Forwarded to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117460, merged-upstream: http://gcc.gnu.org/PR91420

Reply or subscribe to this bug.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to [email protected], [email protected], Daniel Baumann <[email protected]>:
Bug#1086791; Package src:lziprecover. (Tue, 05 Nov 2024 21:30:01 GMT) (full text, mbox, link).


Acknowledgement sent to Aurelien Jarno <[email protected]>:
New Bug report received and forwarded. Copy sent to [email protected], Daniel Baumann <[email protected]>. (Tue, 05 Nov 2024 21:30:01 GMT) (full text, mbox, link).


Message #5 received at [email protected] (full text, mbox, reply):

From: Aurelien Jarno <[email protected]>
To: Debian Bug Tracking System <[email protected]>
Subject: lziprecover: FTBFS on riscv64 due to out-of-bounds access on a constant
Date: Tue, 05 Nov 2024 22:27:00 +0100
Source: lziprecover
Version: 1.25~pre1-1
Severity: serious
Tags: ftbfs upstream
Justification: fails to build from source (but built successfully in the past)
X-Debbugs-Cc: [email protected]
User: [email protected]
Usertags: riscv64

Dear maintainer,

lziprecover fails to build on riscv64 with the following error:

| riscv64-linux-gnu-g++ -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -fstack-protector-strong -Wformat -Werror=format-security -DPROGVERSION=\"1.25-pre1\" -c -o main.o main.cc
| riscv64-linux-gnu-g++ -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -fstack-protector-strong -Wformat -Werror=format-security -Wl,-z,relro -o lziprecover arg_parser.o alone_to_lz.o lzip_index.o list.o byte_repair.o dump_remove.o fec_create.o fec_repair.o gf8.o gf16.o lunzcrash.o md5.o merge.o mtester.o nrep_stats.o range_dec.o recursive.o reproduce.o split.o decoder.o main.o -lpthread
| main.o: in function `(anonymous namespace)::set_mode((anonymous namespace)::Mode&, (anonymous namespace)::Mode) [clone .part.0]':
| /usr/include/riscv64-linux-gnu/bits/stdio2.h:111:(.text+0x8b0): relocation truncated to fit: R_RISCV_PCREL_HI20 against `.LC15'
| collect2: error: ld returned 1 exit status
| make[1]: *** [Makefile:49: lziprecover] Error 1
| make[1]: Leaving directory '/<<PKGBUILDDIR>>'
| dh_auto_build: error: make -j4 returned exit code 2
| make: *** [debian/rules:6: binary-arch] Error 25
| dpkg-buildpackage: error: debian/rules binary-arch subprocess returned exit status 2
| --------------------------------------------------------------------------------

The full build log is available there:
https://buildd.debian.org/status/fetch.php?pkg=lziprecover&arch=riscv64&ver=1.25%7Epre1-1&stamp=1728351091&raw=0

After investigation, I have found that this problem occurs when the
compiler inlines the newly added compare_prefix() function. This causes
an out-of-bound access on a constant. This function is, for instance,
called in parse_fec() that way:

|   else if( compare_prefix( arg, "repair" ) )
|       set_mode( program_mode, m_fec_repair );

With the default arguments like in the above calls, compare_prefix() can be
simplified as:

| // return true if arg is a non-empty prefix of target
| bool compare_prefix( const char * const arg, const char * const target)
|   {   
|   if( arg[0] == target[0] )
|     for( int i = 1; i < INT_MAX; ++i )
|       {                         
|       if( arg[i] == 0 ) return true;
|       if( arg[i] != target[i] ) break;
|       }
|   return false;
|   }

As you can see if the length of the arg string is longer than the target
string, the latter is accessed out-of-bounds, possibly up to INT_MAX.
Probably INT_MAX should be replaced by "strlen(target) + 1".

Regards
Aurelien



Information forwarded to [email protected], Daniel Baumann <[email protected]>:
Bug#1086791; Package src:lziprecover. (Tue, 05 Nov 2024 21:51:01 GMT) (full text, mbox, link).


Acknowledgement sent to Jessica Clarke <[email protected]>:
Extra info received and forwarded to list. Copy sent to Daniel Baumann <[email protected]>. (Tue, 05 Nov 2024 21:51:01 GMT) (full text, mbox, link).


Message #10 received at [email protected] (full text, mbox, reply):

From: Jessica Clarke <[email protected]>
To: [email protected]
Cc: Aurelien Jarno <[email protected]>
Subject: Re: Bug#1086791: lziprecover: FTBFS on riscv64 due to out-of-bounds access on a constant
Date: Tue, 5 Nov 2024 21:47:24 +0000
On 5 Nov 2024, at 21:27, Aurelien Jarno <[email protected]> wrote:
> 
> Source: lziprecover
> Version: 1.25~pre1-1
> Severity: serious
> Tags: ftbfs upstream
> Justification: fails to build from source (but built successfully in the past)
> X-Debbugs-Cc: [email protected]
> User: [email protected]
> Usertags: riscv64
> 
> Dear maintainer,
> 
> lziprecover fails to build on riscv64 with the following error:
> 
> | riscv64-linux-gnu-g++ -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -fstack-protector-strong -Wformat -Werror=format-security -DPROGVERSION=\"1.25-pre1\" -c -o main.o main.cc
> | riscv64-linux-gnu-g++ -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -fstack-protector-strong -Wformat -Werror=format-security -Wl,-z,relro -o lziprecover arg_parser.o alone_to_lz.o lzip_index.o list.o byte_repair.o dump_remove.o fec_create.o fec_repair.o gf8.o gf16.o lunzcrash.o md5.o merge.o mtester.o nrep_stats.o range_dec.o recursive.o reproduce.o split.o decoder.o main.o -lpthread
> | main.o: in function `(anonymous namespace)::set_mode((anonymous namespace)::Mode&, (anonymous namespace)::Mode) [clone .part.0]':
> | /usr/include/riscv64-linux-gnu/bits/stdio2.h:111:(.text+0x8b0): relocation truncated to fit: R_RISCV_PCREL_HI20 against `.LC15'
> | collect2: error: ld returned 1 exit status
> | make[1]: *** [Makefile:49: lziprecover] Error 1
> | make[1]: Leaving directory '/<<PKGBUILDDIR>>'
> | dh_auto_build: error: make -j4 returned exit code 2
> | make: *** [debian/rules:6: binary-arch] Error 25
> | dpkg-buildpackage: error: debian/rules binary-arch subprocess returned exit status 2
> | --------------------------------------------------------------------------------
> 
> The full build log is available there:
> https://buildd.debian.org/status/fetch.php?pkg=lziprecover&arch=riscv64&ver=1.25%7Epre1-1&stamp=1728351091&raw=0
> 
> After investigation, I have found that this problem occurs when the
> compiler inlines the newly added compare_prefix() function. This causes
> an out-of-bound access on a constant. This function is, for instance,
> called in parse_fec() that way:
> 
> |   else if( compare_prefix( arg, "repair" ) )
> |       set_mode( program_mode, m_fec_repair );
> 
> With the default arguments like in the above calls, compare_prefix() can be
> simplified as:
> 
> | // return true if arg is a non-empty prefix of target
> | bool compare_prefix( const char * const arg, const char * const target)
> |   {   
> |   if( arg[0] == target[0] )
> |     for( int i = 1; i < INT_MAX; ++i )
> |       {                         
> |       if( arg[i] == 0 ) return true;
> |       if( arg[i] != target[i] ) break;
> |       }
> |   return false;
> |   }
> 
> As you can see if the length of the arg string is longer than the target
> string, the latter is accessed out-of-bounds, possibly up to INT_MAX.

That’s not true. For the next iteration of the loop to occur, arg[i] !=
0 and arg[i] == target[i], therefore target[i] != 0 and thus the end of
target has not been reached yet. Or, put another way, if we ever reach
the end of target, either arg[i] == target[i] == 0 and so we return
true, or arg[i] != target[i] == 0 and so we break out of the loop (and
return false). This looks completely fine from that perspective to me,
with one exception, if arg and target are both the empty string then we
walk off the end (there should be a check for arg[0] != 0 in the outer
if). But presumably one argument is always a string literal rather than
external input so is known to not be empty. Or so we hope.

The error above is that there’s a signed 32-bit PC-relative relocation
whose value is truncated. That is, the binary is too big for the code
model in use. Perhaps what you’re noticing is that previously it was
just fine, but inlining has increased the code size and pushed it past
the limit. Does the binary embed large arrays of data?

Jess

> Probably INT_MAX should be replaced by "strlen(target) + 1”.





Information forwarded to [email protected], Daniel Baumann <[email protected]>:
Bug#1086791; Package src:lziprecover. (Tue, 05 Nov 2024 22:48:01 GMT) (full text, mbox, link).


Acknowledgement sent to Aurelien Jarno <[email protected]>:
Extra info received and forwarded to list. Copy sent to Daniel Baumann <[email protected]>. (Tue, 05 Nov 2024 22:48:02 GMT) (full text, mbox, link).


Message #15 received at [email protected] (full text, mbox, reply):

From: Aurelien Jarno <[email protected]>
To: Jessica Clarke <[email protected]>
Cc: [email protected], [email protected]
Subject: Re: Bug#1086791: lziprecover: FTBFS on riscv64 due to out-of-bounds access on a constant
Date: Tue, 5 Nov 2024 23:45:20 +0100
control: severity -1 important
control: reassign -1 gcc-14
control: retitle -1 gcc: riscv64 backend emits large relocations due to loop strength reduction
control: forwarded -1 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117460
control: affects -1 lziprecover

On 2024-11-05 21:47, Jessica Clarke wrote:
> On 5 Nov 2024, at 21:27, Aurelien Jarno <[email protected]> wrote:
> > 
> > Source: lziprecover
> > Version: 1.25~pre1-1
> > Severity: serious
> > Tags: ftbfs upstream
> > Justification: fails to build from source (but built successfully in the past)
> > X-Debbugs-Cc: [email protected]
> > User: [email protected]
> > Usertags: riscv64
> > 
> > Dear maintainer,
> > 
> > lziprecover fails to build on riscv64 with the following error:
> > 
> > | riscv64-linux-gnu-g++ -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -fstack-protector-strong -Wformat -Werror=format-security -DPROGVERSION=\"1.25-pre1\" -c -o main.o main.cc
> > | riscv64-linux-gnu-g++ -g -O2 -ffile-prefix-map=/<<PKGBUILDDIR>>=. -fstack-protector-strong -Wformat -Werror=format-security -Wl,-z,relro -o lziprecover arg_parser.o alone_to_lz.o lzip_index.o list.o byte_repair.o dump_remove.o fec_create.o fec_repair.o gf8.o gf16.o lunzcrash.o md5.o merge.o mtester.o nrep_stats.o range_dec.o recursive.o reproduce.o split.o decoder.o main.o -lpthread
> > | main.o: in function `(anonymous namespace)::set_mode((anonymous namespace)::Mode&, (anonymous namespace)::Mode) [clone .part.0]':
> > | /usr/include/riscv64-linux-gnu/bits/stdio2.h:111:(.text+0x8b0): relocation truncated to fit: R_RISCV_PCREL_HI20 against `.LC15'
> > | collect2: error: ld returned 1 exit status
> > | make[1]: *** [Makefile:49: lziprecover] Error 1
> > | make[1]: Leaving directory '/<<PKGBUILDDIR>>'
> > | dh_auto_build: error: make -j4 returned exit code 2
> > | make: *** [debian/rules:6: binary-arch] Error 25
> > | dpkg-buildpackage: error: debian/rules binary-arch subprocess returned exit status 2
> > | --------------------------------------------------------------------------------
> > 
> > The full build log is available there:
> > https://buildd.debian.org/status/fetch.php?pkg=lziprecover&arch=riscv64&ver=1.25%7Epre1-1&stamp=1728351091&raw=0
> > 
> > After investigation, I have found that this problem occurs when the
> > compiler inlines the newly added compare_prefix() function. This causes
> > an out-of-bound access on a constant. This function is, for instance,
> > called in parse_fec() that way:
> > 
> > |   else if( compare_prefix( arg, "repair" ) )
> > |       set_mode( program_mode, m_fec_repair );
> > 
> > With the default arguments like in the above calls, compare_prefix() can be
> > simplified as:
> > 
> > | // return true if arg is a non-empty prefix of target
> > | bool compare_prefix( const char * const arg, const char * const target)
> > |   {   
> > |   if( arg[0] == target[0] )
> > |     for( int i = 1; i < INT_MAX; ++i )
> > |       {                         
> > |       if( arg[i] == 0 ) return true;
> > |       if( arg[i] != target[i] ) break;
> > |       }
> > |   return false;
> > |   }
> > 
> > As you can see if the length of the arg string is longer than the target
> > string, the latter is accessed out-of-bounds, possibly up to INT_MAX.
> 
> That’s not true. For the next iteration of the loop to occur, arg[i] !=
> 0 and arg[i] == target[i], therefore target[i] != 0 and thus the end of
> target has not been reached yet. Or, put another way, if we ever reach
> the end of target, either arg[i] == target[i] == 0 and so we return
> true, or arg[i] != target[i] == 0 and so we break out of the loop (and
> return false). This looks completely fine from that perspective to me,
> with one exception, if arg and target are both the empty string then we
> walk off the end (there should be a check for arg[0] != 0 in the outer
> if). But presumably one argument is always a string literal rather than
> external input so is known to not be empty. Or so we hope.
> 
> The error above is that there’s a signed 32-bit PC-relative relocation
> whose value is truncated. That is, the binary is too big for the code
> model in use. Perhaps what you’re noticing is that previously it was
> just fine, but inlining has increased the code size and pushed it past
> the limit. Does the binary embed large arrays of data?

We continued the discussion on IRC, and Jessica pointed me that's
actually a GCC bug that I have now reported upstream. I am therefore
retitling and reassigning this bug accordingly.

Regards
Aurelien 

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
[email protected]                     http://aurel32.net



Severity set to 'important' from 'serious' Request was from Aurelien Jarno <[email protected]> to [email protected]. (Tue, 05 Nov 2024 22:48:02 GMT) (full text, mbox, link).


Bug reassigned from package 'src:lziprecover' to 'gcc-14'. Request was from Aurelien Jarno <[email protected]> to [email protected]. (Tue, 05 Nov 2024 22:48:02 GMT) (full text, mbox, link).


No longer marked as found in versions lziprecover/1.25~pre1-1. Request was from Aurelien Jarno <[email protected]> to [email protected]. (Tue, 05 Nov 2024 22:48:02 GMT) (full text, mbox, link).


Changed Bug title to 'gcc: riscv64 backend emits large relocations due to loop strength reduction' from 'lziprecover: FTBFS on riscv64 due to out-of-bounds access on a constant'. Request was from Aurelien Jarno <[email protected]> to [email protected]. (Tue, 05 Nov 2024 22:48:02 GMT) (full text, mbox, link).


Set Bug forwarded-to-address to 'https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117460'. Request was from Aurelien Jarno <[email protected]> to [email protected]. (Tue, 05 Nov 2024 22:48:03 GMT) (full text, mbox, link).


Added indication that 1086791 affects lziprecover Request was from Aurelien Jarno <[email protected]> to [email protected]. (Tue, 05 Nov 2024 22:48:03 GMT) (full text, mbox, link).


Changed Bug forwarded-to-address to 'https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117460, merged-upstream: http://gcc.gnu.org/PR91420' from 'https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117460'. Request was from [email protected] to [email protected]. (Mon, 11 Nov 2024 17:39:05 GMT) (full text, mbox, link).


Send a report that this bug log contains spam.


Debian bug tracking system administrator <[email protected]>. Last modified: Tue May 13 05:31:53 2025; Machine Name: buxtehude

Debian Bug tracking system

Debbugs is free software and licensed under the terms of the GNU General Public License version 2. The current version can be obtained from https://bugs.debian.org/debbugs-source/.

Copyright © 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson, 2005-2017 Don Armstrong, and many other contributors.