• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37891

02 Sep 2024 03:17AM UTC coverage: 86.931% (-0.8%) from 87.765%
#37891

push

local

web-flow
Fix errant lmul! for tridiagonal and triangular (#55546)

This method is incorrect. Firstly, the current implementation doesn't
act in-place. Secondly, the result can't be stored in-place into a
triangular matrix in general. This PR changes the implementation to
convert the tridiagonal matrix to a `Diagonal` or a `Bidiagonal` one
before attempting the `lmul!`.
Currently,
```julia
julia> T = Tridiagonal([1,2], [1,2,3], [1,2]); U = UpperTriangular(fill(2, 3, 3));

julia> lmul!(T, U)
3×3 Matrix{Int64}:
 2  4   4
 2  6  10
 0  4  10

julia> U # not updated
3×3 UpperTriangular{Int64, Matrix{Int64}}:
 2  2  2
 â‹…  2  2
 â‹…  â‹…  2

julia> parent(U) # except for the underlying storage
3×3 Matrix{Int64}:
 2  2  2
 0  2  2
 0  0  2
```
After this,
```julia
julia> lmul!(T, U)
ERROR: ArgumentError: matrix cannot be represented as Bidiagonal
```

I'm unsure if we want this method at all, since there isn't a
corresponding `rmul!`, but I've left it there to avoid breakages, if
any.

77318 of 88942 relevant lines covered (86.93%)

15861165.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.47
/base/stacktraces.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
Tools for collecting and manipulating stack traces. Mainly used for building errors.
5
"""
6
module StackTraces
7

8

9
import Base: hash, ==, show
10
import Core: CodeInfo, MethodInstance
11
using Base.IRShow: normalize_method_name, append_scopes!, LineInfoNode
12

13
export StackTrace, StackFrame, stacktrace
14

15
"""
16
    StackFrame
17

18
Stack information representing execution context, with the following fields:
19

20
- `func::Symbol`
21

22
  The name of the function containing the execution context.
23

24
- `linfo::Union{Method, Core.MethodInstance, Core.CodeInfo, Nothing}`
25

26
  The Method, MethodInstance, or CodeInfo containing the execution context (if it could be found), \
27
     or nothing (for example, if the inlining was a result of macro expansion).
28

29
- `file::Symbol`
30

31
  The path to the file containing the execution context.
32

33
- `line::Int`
34

35
  The line number in the file containing the execution context.
36

37
- `from_c::Bool`
38

39
  True if the code is from C.
40

41
- `inlined::Bool`
42

43
  True if the code is from an inlined frame.
44

45
- `pointer::UInt64`
46

47
  Representation of the pointer to the execution context as returned by `backtrace`.
48

49
"""
50
struct StackFrame # this type should be kept platform-agnostic so that profiles can be dumped on one machine and read on another
51
    "the name of the function containing the execution context"
34,651✔
52
    func::Symbol
53
    "the path to the file containing the execution context"
54
    file::Symbol
55
    "the line number in the file containing the execution context"
56
    line::Int
57
    "the MethodInstance or CodeInfo containing the execution context (if it could be found), \
58
     or nothing (for example, if the inlining was a result of macro expansion)."
59
    linfo::Union{MethodInstance, Method, CodeInfo, Nothing}
60
    "true if the code is from C"
61
    from_c::Bool
62
    "true if the code is from an inlined frame"
63
    inlined::Bool
64
    "representation of the pointer to the execution context as returned by `backtrace`"
65
    pointer::UInt64  # Large enough to be read losslessly on 32- and 64-bit machines.
66
end
67

68
StackFrame(func, file, line) = StackFrame(Symbol(func), Symbol(file), line,
×
69
                                          nothing, false, false, 0)
70

71
"""
72
    StackTrace
73

74
An alias for `Vector{StackFrame}` provided for convenience; returned by calls to
75
`stacktrace`.
76
"""
77
const StackTrace = Vector{StackFrame}
78

79
const empty_sym = Symbol("")
80
const UNKNOWN = StackFrame(empty_sym, empty_sym, -1, nothing, true, false, 0) # === lookup(C_NULL)
81

82

83
#=
84
If the StackFrame has function and line information, we consider two of them the same if
85
they share the same function/line information.
86
=#
87
function ==(a::StackFrame, b::StackFrame)
1✔
88
    return a.line == b.line && a.from_c == b.from_c && a.func == b.func && a.file == b.file && a.inlined == b.inlined # excluding linfo and pointer
69,582✔
89
end
90

91
function hash(frame::StackFrame, h::UInt)
92
    h += 0xf4fbda67fe20ce88 % UInt
×
93
    h = hash(frame.line, h)
1,279,039✔
94
    h = hash(frame.file, h)
1,279,039✔
95
    h = hash(frame.func, h)
1,279,039✔
96
    h = hash(frame.from_c, h)
1,279,039✔
97
    h = hash(frame.inlined, h)
1,279,039✔
98
    return h
×
99
end
100

101
"""
102
    lookup(pointer::Ptr{Cvoid}) -> Vector{StackFrame}
103

104
Given a pointer to an execution context (usually generated by a call to `backtrace`), looks
105
up stack frame context information. Returns an array of frame information for all functions
106
inlined at that point, innermost function first.
107
"""
108
Base.@constprop :none function lookup(pointer::Ptr{Cvoid})
19,374✔
109
    infos = ccall(:jl_lookup_code_address, Any, (Ptr{Cvoid}, Cint), pointer, false)::Core.SimpleVector
19,374✔
110
    pointer = convert(UInt64, pointer)
19,374✔
111
    isempty(infos) && return [StackFrame(empty_sym, empty_sym, -1, nothing, true, false, pointer)] # this is equal to UNKNOWN
19,374✔
112
    res = Vector{StackFrame}(undef, length(infos))
38,748✔
113
    for i in 1:length(infos)
19,374✔
114
        info = infos[i]::Core.SimpleVector
33,491✔
115
        @assert(length(info) == 6)
33,491✔
116
        func = info[1]::Symbol
33,491✔
117
        file = info[2]::Symbol
33,491✔
118
        linenum = info[3]::Int
33,491✔
119
        linfo = info[4]
33,491✔
120
        res[i] = StackFrame(func, file, linenum, linfo, info[5]::Bool, info[6]::Bool, pointer)
33,491✔
121
    end
47,608✔
122
    return res
19,374✔
123
end
124

125
const top_level_scope_sym = Symbol("top-level scope")
126

127
function lookup(ip::Union{Base.InterpreterIP,Core.Compiler.InterpreterIP})
218✔
128
    code = ip.code
218✔
129
    if code === nothing
218✔
130
        # interpreted top-level expression with no CodeInfo
131
        return [StackFrame(top_level_scope_sym, empty_sym, 0, nothing, false, false, 0)]
2✔
132
    end
133
    # prepare approximate code info
134
    if code isa MethodInstance && (meth = code.def; meth isa Method)
216✔
135
        func = meth.name
×
136
        file = meth.file
×
137
        line = meth.line
×
138
        codeinfo = meth.source
×
139
    else
140
        if code isa Core.CodeInstance
216✔
141
            codeinfo = code.inferred::CodeInfo
×
142
        else
143
            codeinfo = code::CodeInfo
216✔
144
        end
145
        func = top_level_scope_sym
3✔
146
        file = empty_sym
3✔
147
        line = Int32(0)
3✔
148
    end
149
    def = (code isa MethodInstance ? code : StackTraces) # Module just used as a token for top-level code
216✔
150
    pc::Int = max(ip.stmt + 1, 0) # n.b. ip.stmt is 0-indexed
216✔
151
    scopes = LineInfoNode[]
216✔
152
    append_scopes!(scopes, pc, codeinfo.debuginfo, def)
216✔
153
    if isempty(scopes)
216✔
154
        return [StackFrame(func, file, line, code, false, false, 0)]
×
155
    end
156
    inlined = false
216✔
157
    scopes = map(scopes) do lno
216✔
158
        if inlined
680✔
159
            def = lno.method
464✔
160
            def isa Union{Method,MethodInstance} || (def = nothing)
928✔
161
        else
162
            def = codeinfo
216✔
163
        end
164
        sf = StackFrame(normalize_method_name(lno.method), lno.file, lno.line, def, false, inlined, 0)
680✔
165
        inlined = true
680✔
166
        return sf
680✔
167
    end
168
    return scopes
216✔
169
end
170

171
"""
172
    stacktrace([trace::Vector{Ptr{Cvoid}},] [c_funcs::Bool=false]) -> StackTrace
173

174
Return a stack trace in the form of a vector of `StackFrame`s. (By default stacktrace
175
doesn't return C functions, but this can be enabled.) When called without specifying a
176
trace, `stacktrace` first calls `backtrace`.
177
"""
178
Base.@constprop :none function stacktrace(trace::Vector{<:Union{Base.InterpreterIP,Core.Compiler.InterpreterIP,Ptr{Cvoid}}}, c_funcs::Bool=false)
55✔
179
    stack = StackTrace()
97✔
180
    for ip in trace
45✔
181
        for frame in lookup(ip)
1,080✔
182
            # Skip frames that come from C calls.
183
            if c_funcs || !frame.from_c
2,789✔
184
                push!(stack, frame)
638✔
185
            end
186
        end
1,447✔
187
    end
1,080✔
188
    return stack
45✔
189
end
190

191
Base.@constprop :none function stacktrace(c_funcs::Bool=false)
×
192
    stack = stacktrace(backtrace(), c_funcs)
×
193
    # Remove frame for this function (and any functions called by this function).
194
    remove_frames!(stack, :stacktrace)
×
195
    # also remove all of the non-Julia functions that led up to this point (if that list is non-empty)
196
    c_funcs && deleteat!(stack, 1:(something(findfirst(frame -> !frame.from_c, stack), 1) - 1))
×
197
    return stack
×
198
end
199

200
"""
201
    remove_frames!(stack::StackTrace, name::Symbol)
202

203
Takes a `StackTrace` (a vector of `StackFrames`) and a function name (a `Symbol`) and
204
removes the `StackFrame` specified by the function name from the `StackTrace` (also removing
205
all frames above the specified function). Primarily used to remove `StackTraces` functions
206
from the `StackTrace` prior to returning it.
207
"""
208
function remove_frames!(stack::StackTrace, name::Symbol)
×
209
    deleteat!(stack, 1:something(findlast(frame -> frame.func == name, stack), 0))
×
210
    return stack
×
211
end
212

213
function remove_frames!(stack::StackTrace, names::Vector{Symbol})
×
214
    deleteat!(stack, 1:something(findlast(frame -> frame.func in names, stack), 0))
×
215
    return stack
×
216
end
217

218
"""
219
    remove_frames!(stack::StackTrace, m::Module)
220

221
Return the `StackTrace` with all `StackFrame`s from the provided `Module` removed.
222
"""
223
function remove_frames!(stack::StackTrace, m::Module)
×
224
    filter!(f -> !from(f, m), stack)
×
225
    return stack
×
226
end
227

228
is_top_level_frame(f::StackFrame) = f.linfo isa CodeInfo || (f.linfo === nothing && f.func === top_level_scope_sym)
5✔
229

230
function show_spec_linfo(io::IO, frame::StackFrame)
2,491✔
231
    linfo = frame.linfo
2,491✔
232
    if linfo === nothing
2,491✔
233
        if frame.func === empty_sym
762✔
234
            print(io, "ip:0x", string(frame.pointer, base=16))
×
235
        elseif frame.func === top_level_scope_sym
762✔
236
            print(io, "top-level scope")
19✔
237
        else
238
            Base.print_within_stacktrace(io, Base.demangle_function_name(string(frame.func)), bold=true)
743✔
239
        end
240
    elseif linfo isa CodeInfo
1,729✔
241
        print(io, "top-level scope")
100✔
242
    elseif linfo isa Module
620✔
243
        Base.print_within_stacktrace(io, Base.demangle_function_name(string(frame.func)), bold=true)
×
244
    elseif linfo isa MethodInstance
1,629✔
245
        def = linfo.def
1,629✔
246
        if def isa Module
1,629✔
247
            Base.show_mi(io, linfo, #=from_stackframe=#true)
×
248
        else
249
            show_spec_sig(io, def, linfo.specTypes)
1,629✔
250
        end
251
    else
252
        m = linfo::Method
×
253
        show_spec_sig(io, m, m.sig)
×
254
    end
255
end
256

257
function show_spec_sig(io::IO, m::Method, @nospecialize(sig::Type))
1,629✔
258
    if get(io, :limit, :false)::Bool
1,280✔
259
        if !haskey(io, :displaysize)
558✔
260
            io = IOContext(io, :displaysize => displaysize(io))
117✔
261
        end
262
    end
263
    argnames = Base.method_argnames(m)
3,258✔
264
    argnames = replace(argnames, :var"#unused#" => :var"")
3,258✔
265
    if m.nkw > 0
1,629✔
266
        # rearrange call kw_impl(kw_args..., func, pos_args...) to func(pos_args...; kw_args)
267
        kwarg_types = Any[ fieldtype(sig, i) for i = 2:(1+m.nkw) ]
352✔
268
        uw = Base.unwrap_unionall(sig)::DataType
309✔
269
        pos_sig = Base.rewrap_unionall(Tuple{uw.parameters[(m.nkw+2):end]...}, sig)
309✔
270
        kwnames = argnames[2:(m.nkw+1)]
618✔
271
        for i = 1:length(kwnames)
309✔
272
            str = string(kwnames[i])::String
352✔
273
            if endswith(str, "...")
352✔
274
                kwnames[i] = Symbol(str[1:end-3])
×
275
            end
276
        end
395✔
277
        Base.show_tuple_as_call(io, m.name, pos_sig;
309✔
278
                                demangle=true,
279
                                kwargs=zip(kwnames, kwarg_types),
280
                                argnames=argnames[m.nkw+2:end])
281
    else
282
        Base.show_tuple_as_call(io, m.name, sig; demangle=true, argnames)
1,320✔
283
    end
284
end
285

286
function show(io::IO, frame::StackFrame)
149✔
287
    show_spec_linfo(io, frame)
149✔
288
    if frame.file !== empty_sym
149✔
289
        file_info = basename(string(frame.file))
142✔
290
        print(io, " at ")
142✔
291
        print(io, file_info, ":")
142✔
292
        if frame.line >= 0
142✔
293
            print(io, frame.line)
142✔
294
        else
295
            print(io, "?")
×
296
        end
297
    end
298
    if frame.inlined
149✔
299
        print(io, " [inlined]")
39✔
300
    end
301
end
302

303
function Base.parentmodule(frame::StackFrame)
304
    linfo = frame.linfo
4,278✔
305
    if linfo isa MethodInstance
4,278✔
306
        def = linfo.def
1,901✔
307
        if def isa Module
1,901✔
308
            return def
×
309
        else
310
            return (def::Method).module
1,901✔
311
        end
312
    elseif linfo isa Method
2,377✔
313
        return linfo.module
×
314
    elseif linfo isa Module
×
315
        return linfo
×
316
    else
317
        # The module is not always available (common reasons include
318
        # frames arising from the interpreter)
319
        nothing
320
    end
321
end
322

323
"""
324
    from(frame::StackFrame, filter_mod::Module) -> Bool
325

326
Return whether the `frame` is from the provided `Module`
327
"""
328
function from(frame::StackFrame, m::Module)
×
329
    return parentmodule(frame) === m
×
330
end
331

332
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc