This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/22595] New: a64l should sign-extend its result when long has more than 32 bit


https://sourceware.org/bugzilla/show_bug.cgi?id=22595

            Bug ID: 22595
           Summary: a64l should sign-extend its result when long has more
                    than 32 bit
           Product: glibc
           Version: 2.28
            Status: UNCONFIRMED
          Severity: minor
          Priority: P2
         Component: libc
          Assignee: unassigned at sourceware dot org
          Reporter: daniel.schemmel at comsys dot rwth-aachen.de
                CC: drepper.fsp at gmail dot com
  Target Milestone: ---

Created attachment 10683
  --> https://sourceware.org/bugzilla/attachment.cgi?id=10683&action=edit
archive containing proposed patches for stdlib/a64l.c and stdlib/test-a64l.c

Following the POSIX specification, a64l should sign-extend its result if the
type long has more than 32 bits
(http://pubs.opengroup.org/onlinepubs/9699919799/).

The glibc implementation, as ell as documentation does not acknowledge that
fact (c.f.
https://www.gnu.org/software/libc/manual/html_node/Encode-Binary-Data.html),
and the implementation.

For example, consider the following test program:

#include <assert.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char** argv) {
        (void)argc; (void)argv;

        char const* s = l64a(0xFFFFFFFFu); // "zzzzz1"
        long result = a64l(s);
        long sign_extended = (long)(int32_t)result;
        assert(sign_extended == result);

        return 0;
}

When compiling it for x64, the assertion fails using glibc. In fact, glibc
contains a test case testing this very input in stdlib/test_a64l.c (line 40,
https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=stdlib/test-a64l.c;hb=HEAD),
but does not sign-extend the result 0xFFFFFFFF to (long)(-1).

Note that this relies on a slightly weird aspect of the POSIX specification:
The lower 32 bit of any long are used for l64a and the behavior is unspecified
if the value is negative. If long has more than 32 bit, it is never negative,
as long as only the lower 32 bit are used! (Note that the glibc implementation
guarantees that the behavior is never unspecified by always treating the
argument as unsigned.)

This allows generating the string "zzzzz1" by giving the (positive) number
2**32-1 to l64a. This in turn ensures that the behavior of a64l is not
unspecified, as the string has been generated by a call to l64a. When undoing
the conversion, the lower 32 bit of the result are 0xFFFFFFFF which, when
sign-extended should yield -1.

As expected, when changing stdlib/test-a64l.c (see stdlib/test-a64l.c.patch in
attached file a64l.txz), the test execution fails.

When enabling sign-extension in a64l (see stdlib/a64l.c.patch in attached file
a64l.txz), it succeeds again.

See also:
- commit fixing a similar bug in musl
https://git.musl-libc.org/cgit/musl/commit/?id=77baaa47e107f176fb2dc150dd6a9ad87f6cbe24

This behavior was detected using Symbolic Execution techniques developed in the
course of the SYMBIOSYS research project at COMSYS, RWTH Aachen University.
This research is supported by the European Research Council (ERC) under the
EU's Horizon 2020 Research and Innovation Programme grant agreement n. 647295
(SYMBIOSYS).

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]