ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.31k stars 2.51k forks source link

translate-c crash, generating invalid AST on floatscan.c #8602

Closed andrewrk closed 3 years ago

andrewrk commented 3 years ago

floatscan.c

#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <float.h>
#include <math.h>
#include <inttypes.h>
static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok)
{
    uint32_t x = 0;
    long double y = 0;
    long double scale = 1;
    long double bias = 0;
    int gottail = 0, gotrad = 0, gotdig = 0;
    long long rp = 0;
    long long dc = 0;
    long long e2 = 0;
    int d;
    int c;

    c = shgetc(f);

    /* Skip leading zeros */
    for (; c=='0'; c = shgetc(f)) gotdig = 1;

    if (c=='.') {
        gotrad = 1;
        c = shgetc(f);
        /* Count zeros after the radix point before significand */
        for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1;
    }

    for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) {
        if (c=='.') {
            if (gotrad) break;
            rp = dc;
            gotrad = 1;
        } else {
            gotdig = 1;
            if (c > '9') d = (c|32)+10-'a';
            else d = c-'0';
            if (dc<8) {
                x = x*16 + d;
            } else if (dc < LDBL_MANT_DIG/4+1) {
                y += d*(scale/=16);
            } else if (d && !gottail) {
                y += 0.5*scale;
                gottail = 1;
            }
            dc++;
        }
    }
    if (!gotdig) {
        shunget(f);
        if (pok) {
            shunget(f);
            if (gotrad) shunget(f);
        } else {
            shlim(f, 0);
        }
        return sign * 0.0;
    }
    if (!gotrad) rp = dc;
    while (dc<8) x *= 16, dc++;
    if ((c|32)=='p') {
        e2 = scanexp(f, pok);
        if (e2 == LLONG_MIN) {
            if (pok) {
                shunget(f);
            } else {
                shlim(f, 0);
                return 0;
            }
            e2 = 0;
        }
    } else {
        shunget(f);
    }
    e2 += 4*rp - 32;

    if (!x) return sign * 0.0;
    if (e2 > -emin) {
        errno = ERANGE;
        return sign * LDBL_MAX * LDBL_MAX;
    }
    if (e2 < emin-2*LDBL_MANT_DIG) {
        errno = ERANGE;
        return sign * LDBL_MIN * LDBL_MIN;
    }

    while (x < 0x80000000) {
        if (y>=0.5) {
            x += x + 1;
            y += y - 1;
        } else {
            x += x;
            y += y;
        }
        e2--;
    }

    if (bits > 32+e2-emin) {
        bits = 32+e2-emin;
        if (bits<0) bits=0;
    }

    if (bits < LDBL_MANT_DIG)
        bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign);

    if (bits<32 && y && !(x&1)) x++, y=0;

    y = bias + sign*(long double)x + sign*y;
    y -= bias;

    if (!y) errno = ERANGE;

    return scalbnl(y, e2);
}
[nix-shell:~/Downloads/zig/build]$ ./zig translate-c floatscan.c -lc -target x86_64-linux-musl
thread 30059 panic: reached unreachable code
/home/andy/Downloads/zig/lib/std/debug.zig:223:14: 0xb477d8 in std.debug.assert (zig1)
    if (!ok) unreachable; // assertion failure
             ^
/home/andy/Downloads/zig/lib/std/zig/ast.zig:114:15: 0xcc5b92 in std.zig.ast.Tree.tokenSlice (zig1)
        assert(token.tag == token_tag);
              ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:2400:30: 0x115563f in std.zig.render.tokenSliceForRender (zig1)
    var ret = tree.tokenSlice(token_index);
                             ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:2205:39: 0x105525e in std.zig.render.renderToken (zig1)
    const lexeme = tokenSliceForRender(tree, token_index);
                                      ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:192:30: 0x115b512 in std.zig.render.renderExpression (zig1)
        => return renderToken(ais, tree, main_tokens[node], space),
                             ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:388:36: 0x1157255 in std.zig.render.renderExpression (zig1)
            return renderExpression(gpa, ais, tree, infix.rhs, space);
                                   ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:533:33: 0x115ccec in std.zig.render.renderExpression (zig1)
            try renderExpression(gpa, ais, tree, datas[node].lhs, .none);
                                ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:378:33: 0x115c461 in std.zig.render.renderExpression (zig1)
            try renderExpression(gpa, ais, tree, infix.lhs, .space);
                                ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:524:37: 0x115cbe1 in std.zig.render.renderExpression (zig1)
                try renderExpression(gpa, ais, tree, datas[node].lhs, space);
                                    ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:1525:45: 0x13366b7 in std.zig.render.renderBlock (zig1)
                else => try renderExpression(gpa, ais, tree, stmt, .semicolon),
                                            ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:235:31: 0x115bbc7 in std.zig.render.renderExpression (zig1)
            return renderBlock(gpa, ais, tree, node, statements, space);
                              ^
/home/andy/Downloads/zig/lib/std/zig/render.zig:1107:33: 0x1344295 in std.zig.render.renderWhile (zig1)
            try renderExpression(gpa, ais, tree, while_node.ast.then_expr, space);
                                ^
LemonBoy commented 3 years ago

The long double constants LDBL_MAX and LDBL_MIN are casted into double by translate-c and become inf, an invalid literal.