Revision 4954af9c5ee5bb1b5b9172ddbcbac03ca6e151ea authored by Keno Fischer on 01 September 2023, 19:52:14 UTC, committed by GitHub on 01 September 2023, 19:52:14 UTC
The change in #50429 moves around some dispatch boundaries and pushes
the allocations in the offsetarrays `maximum!` test over the limit. The
implementation of that code is massively type unstable. Somewhat,
ironically, the whole original point of that test was to test that the
implementation was not type-unstable (#28941), so actually opt our
OffsetArrays implementation into the interface that's supposed to
guarantee that.

If this PR is fine here, I'll submit the same upstream to avoid
diverging the implementations too much.

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
1 parent a173010
Raw File
secretbuffer.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Base: SecretBuffer, SecretBuffer!, shred!, isshredded
using Test

@testset "SecretBuffer" begin
    @testset "original unmodified" begin
        str = "foobar"
        secret = SecretBuffer(str)

        @test read(secret, String) == str
        seekstart(secret)

        @test peek(secret) == 0x66

        @test shred!(secret) === secret
        @test read(secret, String) == ""
        @test str == "foobar"
    end

    @testset "finalizer" begin
        v = UInt8[1, 2]
        secret_a = SecretBuffer!(v)
        secret_b = secret_a

        secret_a = nothing
        GC.gc()

        @test all(iszero, v)
        @test !isshredded(secret_b)

        # TODO: ideally we'd test that the finalizer warns from GC.gc(), but that is harder
        @test_logs (:warn, r".*SecretBuffer was `shred!`ed by the GC.*") begin
            finalize(secret_b)
            # Allow the async task which produces the SecretBuffer warning to run.
            # This is a hack, but we don't have a way to get a handle to that
            # task in order to `wait` on it.
            for i=1:1000
                yield()
            end
        end
        @test isshredded(secret_b)
        secret_b = nothing
        GC.gc()
    end

    @testset "initializers" begin
        s1 = SecretBuffer("setec astronomy")
        data2 = [0x73, 0x65, 0x74, 0x65, 0x63, 0x20, 0x61, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x6f, 0x6d, 0x79]
        s2 = SecretBuffer!(data2)
        @test all(==(0x0), data2)
        @test s1 == s2

        ptr3 = Base.unsafe_convert(Cstring, "setec astronomy")
        s3 = Base.unsafe_SecretBuffer!(ptr3)
        @test Base.unsafe_string(ptr3) == ""
        @test s1 == s2 == s3

        s4 = SecretBuffer(split("setec astronomy", " ")[1]) # initialize from SubString
        s5 = convert(SecretBuffer, split("setec astronomy", " ")[1]) # initialize from SubString
        @test s4 == s5
        shred!(s1); shred!(s2); shred!(s3); shred!(s4), shred!(s5);
    end
    @testset "basics" begin
        s1 = SecretBuffer("setec astronomy")
        @test sprint(show, s1) == "SecretBuffer(\"*******\")"
        @test !isempty(s1)
        shred!(s1)
        s2 = SecretBuffer!([0x00])
        @test_throws ArgumentError Base.cconvert(Cstring, s2)
        shred!(s2)
    end
    @testset "write! past data size" begin
        sb = SecretBuffer(sizehint=2)
        # data vector will not grow
        bits = typemax(UInt8)
        write(sb, bits)
        write(sb, bits)
        # data vector must grow
        write(sb, bits)
        seek(sb, 0)
        @test read(sb, String) == "\xff\xff\xff"
        shred!(sb)
    end
    @testset "bytes available" begin
        sb = SecretBuffer("secret")
        @test bytesavailable(sb) == sb.size
        seek(sb, 3)
        @test bytesavailable(sb) == sb.size - 3
        seekend(sb)
        @test bytesavailable(sb) == 0
        shred!(sb)
    end
    @testset "testing the skip function" begin
        sb = SecretBuffer("computer")
        skip(sb, 2)
        @test position(sb) == 2
        seek(sb, 0)
        @test position(sb) == 0
        skip(sb, sb.size)
        @test position(sb) == sb.size
        shred!(sb)
    end
    @testset "seekend" begin
        sb = SecretBuffer("hello")
        seekend(sb)
        @test read(sb, String) == ""
        shred!(sb)
    end
    @testset "position" begin
        sb = SecretBuffer("Julia")
        initial_pos = (position(sb))
        seek(sb,2)
        mid_pos = position(sb)
        seekend(sb)
        @test initial_pos == 0 && mid_pos == 2 && position(sb)==sb.size
        shred!(sb)
    end
    @testset "hashing secret buffers" begin
        sb1 = SecretBuffer("hello")
        sb2 = SecretBuffer("juliaisawesome")
        @test hash(sb1, UInt(5)) === hash(sb2, UInt(5))
        shred!(sb1); shred!(sb2)
    end
    @testset "NULL initialization" begin
        null_ptr = Cstring(C_NULL)
        @test_throws ArgumentError Base.unsafe_SecretBuffer!(null_ptr)
        null_ptr = Ptr{UInt8}(C_NULL)
        @test_throws ArgumentError Base.unsafe_SecretBuffer!(null_ptr)
        @test_throws ArgumentError Base.unsafe_SecretBuffer!(null_ptr, 0)
    end
end
back to top