Skip to content
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

reader.readAllAlloc crash on Ampere a1 CPU when given a much larger max_size parameter than the actual file size #20714

Open
WeijieH opened this issue Jul 21, 2024 · 4 comments · May be fixed by #20511
Labels
bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. standard library This issue involves writing Zig code for the standard library.
Milestone

Comments

@WeijieH
Copy link

WeijieH commented Jul 21, 2024

Zig Version

0.14.0-dev.367+a57479afc

Steps to Reproduce and Observed Behavior

Example zig code:

const std = @import("std");
const fs = std.fs;
const print = std.debug.print;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const file = try fs.cwd().openFile("crash.txt", .{});
    defer file.close();

    var buf_reader = std.io.bufferedReader(file.reader());
    const reader = buf_reader.reader();

    const buffer = try reader.readAllAlloc(allocator, 10240);
    defer allocator.free(buffer);

    print("{s}\n", .{buffer});
}

And crash.txt with only 5 letters:

crash

And run $ zig run example.zig will result in a crash:

thread 2442597 panic: reached unreachable code
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/posix.zig:4699:19: 0x104fa9f in munmap (t)
        .INVAL => unreachable, // Invalid parameters.
                  ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/heap/PageAllocator.zig:94:21: 0x104f9c3 in resize (t)
        posix.munmap(@alignCast(ptr[0 .. buf_aligned_len - new_size_aligned]));
                    ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/mem/Allocator.zig:92:30: 0x107a923 in resizeLarge (t)
    return self.vtable.resize(self.ptr, buf, log2_buf_align, new_len, ret_addr);
                             ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/heap/general_purpose_allocator.zig:722:40: 0x104fecf in resize (t)
                return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr);
                                       ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/mem/Allocator.zig:92:30: 0x107d6e3 in resize__anon_7795 (t)
    return self.vtable.resize(self.ptr, buf, log2_buf_align, new_len, ret_addr);
                             ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/array_list.zig:1010:33: 0x1096e6f in shrinkAndFree (t)
            if (allocator.resize(old_memory, new_len)) {
                                ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/array_list.zig:398:36: 0x108b5bb in shrinkAndFree (t)
            unmanaged.shrinkAndFree(self.allocator, new_len);
                                   ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/io/Reader.zig:76:37: 0x107d443 in readAllArrayListAligned__anon_7794 (t)
            array_list.shrinkAndFree(start_index);
                                    ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/io/Reader.zig:52:40: 0x1052363 in readAllArrayList (t)
    return self.readAllArrayListAligned(null, array_list, max_append_size);
                                       ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/io/Reader.zig:92:30: 0x104c60f in readAllAlloc (t)
    try self.readAllArrayList(&array_list, max_size);
                             ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/io.zig:135:54: 0x104bf7f in main (t)
            return @errorCast(self.any().readAllAlloc(allocator, max_size));
                                                     ^
/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/start.zig:532:37: 0x104bd1f in posixCallMainAndExit (t)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x0 in ??? (???)
Aborted (core dumped)

To avoid crash, I can either change const buffer = try reader.readAllAlloc(allocator, 10240); to const buffer = try reader.readAllAlloc(allocator, 1024);
or read a different file with more text in it. For example, the same text file but with with 999 lines of 'crash'

I only observed this behavior on my Oracle Cloud Ampere A1 CPU machines. I don't have other aarch64 machines to test so I'm not sure if this is Ampere A1 CPU only.
Same code will run on x64 windows and x64 linux without any problems.

Expected Behavior

readAllAlloc should read the file without crash

@WeijieH WeijieH added the bug Observed behavior contradicts documented or intended behavior label Jul 21, 2024
@andrewrk andrewrk added this to the 0.14.0 milestone Jul 26, 2024
@andrewrk andrewrk added contributor friendly This issue is limited in scope and/or knowledge of Zig internals. standard library This issue involves writing Zig code for the standard library. labels Jul 26, 2024
@gcoakes
Copy link
Contributor

gcoakes commented Aug 3, 2024

Could not reproduce with -target aarch64-linux via qemu-user:

details
$ zig version
0.14.0-dev.367+a57479afc
$ zig run -target aarch64-linux repro.zig
crash

The following lines from the original report seem to indicate a syscall gave the OS an unexpected value.

/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/posix.zig:4699:19: 0x104fa9f in munmap (t)
        .INVAL => unreachable, // Invalid parameters.

Linux's manpage for munmap indicates pointer must be aligned to the page size whereas length does not.

@WeijieH, could you please do the following:

  1. Clarify what OS you're using.
  2. Run and report the output of (EDIT: added PAGE_SIZE print):
$ zig build-exe repro.zig
$ strace --trace=munmap,mmap ./repro
$ getconf PAGE_SIZE

@alexrp
Copy link
Contributor

alexrp commented Aug 3, 2024

Very strongly suspect this is a duplicate of #16331, or closely related.

@WeijieH
Copy link
Author

WeijieH commented Aug 6, 2024

Could not reproduce with -target aarch64-linux via qemu-user:

details
The following lines from the original report seem to indicate a syscall gave the OS an unexpected value.

/home/opc/zig-linux-aarch64-0.14.0-dev.367+a57479afc/lib/std/posix.zig:4699:19: 0x104fa9f in munmap (t)
        .INVAL => unreachable, // Invalid parameters.

Linux's manpage for munmap indicates pointer must be aligned to the page size whereas length does not.

@WeijieH, could you please do the following:

  1. Clarify what OS you're using.
  2. Run and report the output of (EDIT: added PAGE_SIZE print):
$ zig build-exe repro.zig
$ strace --trace=munmap,mmap ./repro
$ getconf PAGE_SIZE

Here is the result of strace:

[opc@instance-20221208-2328 test]$ strace --trace=munmap,mmap ./t
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef910000
mmap(0xfffeef911000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef900000
munmap(0xfffeef901000, 4096)            = -1 EINVAL (Invalid argument)
thread 3648566 panic: reached unreachable code
mmap(0xfffeef902000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef8f0000
mmap(NULL, 2554264, PROT_READ, MAP_SHARED, 4, 0) = 0xfffeef680000
mmap(0xfffeef8f1000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef670000
mmap(0xfffeef672000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef660000
mmap(0xfffeef664000, 45056, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef650000
mmap(0xfffeef65b000, 147456, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef620000
mmap(0xfffeef644000, 495616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffeef5a0000
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/posix.zig:4731:19: 0x104e6f7 in munmap (t)
        .INVAL => unreachable, // Invalid parameters.
                  ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/heap/PageAllocator.zig:94:21: 0x104e61b in resize (t)
        posix.munmap(@alignCast(ptr[0 .. buf_aligned_len - new_size_aligned]));
                    ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/mem/Allocator.zig:92:30: 0x1078f4f in resizeLarge (t)
    return self.vtable.resize(self.ptr, buf, log2_buf_align, new_len, ret_addr);
                             ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/heap/general_purpose_allocator.zig:722:40: 0x104eb27 in resize (t)
                return self.resizeLarge(old_mem, log2_old_align, new_size, ret_addr);
                                       ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/mem/Allocator.zig:92:30: 0x107bbcf in resize__anon_7814 (t)
    return self.vtable.resize(self.ptr, buf, log2_buf_align, new_len, ret_addr);
                             ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/array_list.zig:1010:33: 0x109546b in shrinkAndFree (t)
            if (allocator.resize(old_memory, new_len)) {
                                ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/array_list.zig:398:36: 0x1089cc7 in shrinkAndFree (t)
            unmanaged.shrinkAndFree(self.allocator, new_len);
                                   ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/io/Reader.zig:76:37: 0x107b92f in readAllArrayListAligned__anon_7813 (t)
            array_list.shrinkAndFree(start_index);
                                    ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/io/Reader.zig:52:40: 0x1050fbb in readAllArrayList (t)
    return self.readAllArrayListAligned(null, array_list, max_append_size);
                                       ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/io/Reader.zig:92:30: 0x104c067 in readAllAlloc (t)
    try self.readAllArrayList(&array_list, max_size);
                             ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/io.zig:135:54: 0x104b9d7 in main (t)
            return @errorCast(self.any().readAllAlloc(allocator, max_size));
                                                     ^
/home/opc/zig/0.14.0-dev.764+eb1a199df/files/lib/std/start.zig:570:37: 0x104b777 in posixCallMainAndExit (t)
            const result = root.main() catch |err| {
                                    ^
???:?:?: 0x0 in ??? (???)
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=3648566, si_uid=1000} ---
+++ killed by SIGABRT (core dumped) +++
Aborted (core dumped)

PAGE_SIZE is 65536

system OS is oracle linux 8 Linux instance-20221208-2328 5.4.17-2136.333.5.el8uek.aarch64 #3 SMP Thu Jun 20 01:09:36 PDT 2024 aarch64 aarch64 aarch64 GNU/Linux

@gcoakes
Copy link
Contributor

gcoakes commented Aug 7, 2024

@WeijieH , I think that confirms what @alexrp said. Misaligned munmap due to an unexpected page size for your platform.

@alexrp alexrp linked a pull request Aug 17, 2024 that will close this issue
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. standard library This issue involves writing Zig code for the standard library.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants