Skip to content

std.fmt: check result types in parseInt functions #24256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ilumys
Copy link

@ilumys ilumys commented Jun 23, 2025

The parseInt() family of functions do not perform type checking thus accepting erroneous inputs for result types.

Sample subject case, built with zig 0.15.0-dev.869+640a13065:

const std = @import("std");

pub fn main() !void {
    const i = "1234";

    // selectively run with any of the following; error is the same
    _ = try std.fmt.parseInt(f32, i, 10);
    // _ = try std.fmt.parseIntWithGenericCharacter(f32, u8, i, 10);
    // _ = try std.fmt.parseUnsigned(f32, i, 10);
}

Outputs:

/home/user/zig/lib/std/fmt.zig:1636:41: error: access of union field 'int' while field 'float' is active
    const Accumulate = std.meta.Int(info.int.signedness, @max(8, info.int.bits));
                                    ~~~~^~~~
/home/user/zig/lib/std/builtin.zig:572:18: note: union declared here
pub const Type = union(enum) {
                 ^~~~~
referenced by:
    parseIntWithGenericCharacter__anon_23506: /home/user/zig/lib/std/fmt.zig:1529:47
    parseInt__anon_23379: /home/user/zig/lib/std/fmt.zig:1518:40
    6 reference(s) hidden; use '-freference-trace=8' to see all references
/home/user/zig/lib/std/fmt.zig:1636:41: error: access of union field 'int' while field 'float' is active
    const Accumulate = std.meta.Int(info.int.signedness, @max(8, info.int.bits));
                                    ~~~~^~~~
/home/user/zig/lib/std/builtin.zig:572:18: note: union declared here
pub const Type = union(enum) {
                 ^~~~~

This PR checks that the given input (T or Result) is an integer and ouputs a compiler error when this is not true. The specific form of error output was taken from prior art in parseFloat(). While the code will not compile without this change, it is desirable to make this a clear compiler error, both to prevent processing of invalid inputs and improve user experience.

Output with patch:

/home/user/zig/lib/std/fmt.zig:1521:9: error: Cannot parse an integer into a non-integer point type.
        @compileError("Cannot parse an integer into a non-integer point type.");
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    main: test/t.zig:7:29
    callMain [inlined]: /home/user/zig/lib/std/start.zig:681:37
    callMainWithArgs [inlined]: /home/user/zig/lib/std/start.zig:641:20
    posixCallMainAndExit: /home/user/zig/lib/std/start.zig:596:36
    2 reference(s) hidden; use '-freference-trace=6' to see all references

parseIntWithSign() is not exported from the container but I believe its inclusion has merit. Type check is compile- time and an assertion of expected input type(s); docs (which, to be fair, are largely taken from other parseInt() fn's) ease readability of source code.

Produces compiler errors on failed checks advising of the cause

Also documents `parseIntWithSign` with reference to `parseInt`
@andrewrk andrewrk self-assigned this Jun 23, 2025
@andrewrk
Copy link
Member

Thanks for the patch. Apologies but I'm going to keep it in limbo until I can get some conflicting work done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants