TGViewer
Channel Public Channel
Telegram github commits and releases

Telegram github commits and releases

@tgappsupdates

Broadcast from the most important Telegram clients' repositories
Subscribers
4.53K
Photos
0
Videos
0
Links
20.7K

Showing posts older than #20517 · Back to latest

Older Posts 20 shown
Post #20515 129
UnigramDev/Unigram/develop • c5beb02 • 3 files, +30/-8
Fix file id packing

UnigramDev/Unigram/develop • b9e38a2 • 10 files, +674/-265
Improve media streaming

UnigramDev/Unigram/develop • e18b2ba • 1 files, +3/-1
Fix conditional check

UnigramDev/Unigram/develop • aabf3a0 • 1 files, +104/-9
Calculate can be forwarded/replied locally in MessageSelector

UnigramDev/Unigram/develop • 1ae3795 • 1 files, +70/-0
Support buttons in text

UnigramDev/Unigram/develop • 7979820 • 2 files, +10/-3
Fix recycle paths

UnigramDev/Unigram/develop • 9a61aba • 2 files, +2/-0
Add handled true where missing

UnigramDev/Unigram/develop • 333170e • 7 files, +14/-0
Add tlottie test

UnigramDev/Unigram/develop • 2a2fd79 • 1 files, +8/-0
Handle unsupported message click

UnigramDev/Unigram/develop • d4268bb • 1 files, +5/-4
Fix quick reply shortcut crash

UnigramDev/Unigram/develop • ee0d49d • 1 files, +5/-0
Handle force reply

UnigramDev/Unigram/develop • 16acb43 • 1 files, +2/-2
Fix rich draft

UnigramDev/Unigram/develop • f2305b4 • 3 files, +80/-100
Text editor improvements

UnigramDev/Unigram/develop • 8bde885 • 1 files, +2/-2
Fix csproj

UnigramDev/Unigram/develop • f046915 • 1 files, +3/-3
Fix AddFileToDownloads calls

#unigram
  • 🫡 2
Post #20514 85
UnigramDev/Unigram/develop • 73fcda9 • 1 files, +26/-4
crash-triage: close the crash group when the PR merges

Merging is what marks a crash fixed, so the loop now ends by closing the
group rather than leaving it to be done by hand.

Because the group hash cannot appear in the PR, the pr-number -> group-hash
mapping has to be recorded locally when the PR is opened, or the link is lost
as soon as the PR is the only artefact left.

Also records the PR-watching gotcha found this session: gh posts comments
under the user's own account, so a watcher cannot use author to tell the
agent's comments from the user's, and unfiltered it reads its own words back
as instructions. Agent comments carry an HTML-comment marker and the watcher
skips them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 4caca6d • 1 files, +17/-0
crash-triage: verify the mechanism instead of inferring it

A rejected PR's worth of lesson. The autocomplete crash was diagnosed as a
recycled container carrying the previous item type's template, a story that
fitted the stack and was never checked. The actual cause was
AutocompleteTemplateSelector returning CommandTemplate for both UserCommand
and QuickReplyShortcut, so the tree never matched what the code-behind read —
one file would have shown it, and it was never opened.

Requires naming and opening the file that would confirm a hypothesis before
writing code, and adds two checks that would have caught this one:

- Does the crash frequency match the story? A race is intermittent; a
mismatched template fails every time that path runs. Rare-but-deterministic
contradicts a race.
- For a visual-tree mismatch, read the DataTemplateSelector before blaming
recycling. Guarding the symptom there turns a crash into a silently blank
row and leaves the real bug in place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • e66dbd0 • 1 files, +14/-0
crash-triage: don't construct singletons to silence a null

Second rejected PR, same root habit as the first: fixing the symptom at the
call site without establishing who owns the state.

InitializeFrame was patched to build a WindowContext when Current was null.
WindowContext's constructor assigns the thread-static _current, and
OnWindowCreated constructs one on its own schedule, so the patch produced two:
the later assignment wins and the frame attached to the first is silently
discarded. That is worse than the NullReferenceException it removed, because
it corrupts startup state instead of aborting it.

Adds two rules:

- Before constructing anything to make a null go away, grep every construction
site and work out the ordering. If it is a not-yet-initialised singleton,
creating one here means two exist and one loses.
- When the missing state is a race, neither inventing it nor returning early
is the fix — returning leaves the feature silently dead, which is the same
trap as guarding a template mismatch. Carrying the input forward until the
state arrives is a sequencing decision about startup: propose it, don't
guess at it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • ecb532a • 1 files, +2/-2
Fix MediaDeviceList release

#unigram
  • 🫡 2
Post #20513 73
UnigramDev/Unigram/develop • a7d3657 • 1 files, +8/-4
Improve quote style

UnigramDev/Unigram/develop • e068bd3 • 1 files, +22/-5
crash-triage: correct the PR base and branch naming

Two things went wrong on the first real run of this skill.

The PR must be based on GitHub's develop, not on origin/develop inside a
clone of the user's repo. That ref is their remote-tracking branch: it was
both stale and carrying unpushed local commits, so it had diverged from the
branch the PR actually merges into, and the file being patched differed
between the two. Add the GitHub remote explicitly and branch from there.

Branches cannot be prefixed with fix/, because a branch literally named "fix"
exists on the remote and git rejects the push with "directory file conflict".

Also requires stating whether the change was built and run. A UWP/.NET Native
build is usually unavailable here, and a reviewer should not have to guess.
Roslyn parsing is offered as the weaker check it is, with its limits spelled
out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 79e90af • 1 files, +20/-7
crash-triage: never publish crash impact numbers

The repository is public, so affected-user counts, device counts and per-OS
breakdowns are private telemetry being published to the world. The PR
template asked for exactly that, and the first real run put "46 crashes / 32
users" into both a PR body and a pushed commit message.

Impact figures are now explicitly for choosing what to work on, never for
justifying it in public. PRs say "reported by crash telemetry on <version>"
and nothing more; group hashes and device breakdowns stay out too.

Calls out that the commit message is as public as the PR body and must be
checked before pushing, since scrubbing it afterwards needs a force-push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 6a24748 • 1 files, +12/-3
crash-triage: generate public text with crashctl --public

Stripping impact figures by hand already failed once, so point the skill at
the mechanical path instead: crashctl show --public emits the exception, the
frames and the missing-symbol list with impact figures, device/OS breakdown,
group hash and log tail withheld.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20512 70
UnigramDev/Unigram/develop • 5082051 • 1 files, +39/-4
crash-triage: make the app log tail a first-class diagnosis step

The log tail is the most useful part of a crash record and was only mentioned
as a flag. The stack says where the app died; the log tail says what it was
doing, which is usually what explains the crash.

Documents both halves: the state header (memory used/available, window size,
scaling, active calls, raw HRESULT) which is worth checking against the crash's
device spread, and the timestamped [File.cs:line][Method] trace, which carries
its own source locations and so corroborates the symbolicated stack
independently.

Diagnosis now requires reconciling stack, log tail and source at the reference
commit, rather than reasoning from the stack alone. Also notes that app logging
is currently sparse, so a missing log line is a legitimate follow-up to raise
in the PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • d36dec9 • 2 files, +48/-0
Handle clicks in gallery

UnigramDev/Unigram/develop • cfff648 • 11 files, +305/-23
Extend the orphan analysis to the gallery and mini apps

Analyze reports whatever is registered but unreachable from the roots it is
given, so it only works as a single call over the union of every area's roots:
running it per area marks every other area's live objects as leaked. ChatView
therefore stops calling it and exposes DebugRoots instead, MainPage assembles
the union, and each area contributes roots and a descent that return nothing for
types they do not own.

The gallery registers what a leak there actually costs: the window, its content
and transport controls, the compact overlay that outlives it on purpose, and the
player base, whose decoder and surfaces are the reason any of this matters. The
window stops being a root once nothing legitimately holds it, so anything still
referencing it past that point is the leak rather than the owner.

WebAppPage joins the same analysis, and its event subscriptions move with it.
Both constructors subscribed Window.Current.Activated, CloseRequested,
Consolidated and VisibleBoundsChanged, and neither unsubscribed, so the page
stayed reachable from the view for as long as the view lived. They now hook and
unhook in the UserControlEx OnLoaded and OnUnloaded pair, which is guaranteed to
alternate; the raw Loaded and Unloaded events fire again on every reparenting,
and CloseRequested and Consolidated take deferrals, so a second handler would
mean a second confirmation dialog rather than merely wasted work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • b239b87 • 15 files, +154/-159
Code cleanup

UnigramDev/Unigram/develop • eb9411e • 7 files, +264/-15979
Improve rich editor

UnigramDev/Unigram/develop • bf24e59 • 2 files, +129/-13
Add buttons support in rich messages

#unigram
  • 🫡 2
Post #20511 69
UnigramDev/Unigram/develop • 5d1c657 • 1 files, +20/-5
Notify the system call of the mute state on the conference path

Both conference constructors called TryNotifyMutedChanged before reserving the
system call, when _coordinator is still null, so the null-conditional swallowed
it and the initial mute state was never handed over. The video chat constructor
called it after, where it works.

Both now go through NotifyMutedChanged after the reservation. That reads the
manager into a local first: it runs after an await, and Dispose clears the field
from whichever thread ends the call.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 196c8df • 1 files, +1/-1
Fix leak on voip coordinator exception

UnigramDev/Unigram/develop • e8922b2 • 1 files, +152/-0
Add crash-triage skill

Encodes the workflow for turning a production crash from the dashboard into a
fix: rank groups by affected users, symbolicate with crashctl, map the
crashing version back to its source, diagnose, and open a PR against develop.

The version mapping is the part worth writing down. Crash line numbers refer
to the released build, so reading them against a working tree silently points
at the wrong code — on the crash checked while writing this, the reported line
2341 lands exactly on the reporting function at the 12.8.1 bump commit, and is
past the end of the file in the current tree. The skill resolves the version
via its tag, falls back to the "Bump version to X" commit when the tag was
never pushed (v12.8.1 is one such case), and then requires verifying that the
reported line actually falls inside the reported function before any code is
read for diagnosis.

Work happens in a local clone, never in the user's working tree. The skill
also records the limits: never close a crash group (only a shipped release
proves a fix), never push to develop/main, and treat crash records as user
data.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • cb35007 • 8 files, +122/-380
Extract the duplicated skeleton placeholder builder

The same shimmer placeholder was written out seven times, in ReactionButton,
InteractionsView, SearchPostsTabPage, ChatView, GiftCraftChoosePopup,
ResoldGiftsPopup and StoryInteractionsPopup. Each built a list of rounded rects,
grouped them into a path geometry, and then repeated an identical gradient,
sprite shapes, clip and sweep animation, differing only in the rectangles.

VisualUtilities.SetSkeleton takes the element, the sweep extent and the shapes.
Two things fell out of merging them: every copy kept separate foreground and
background colours that were always assigned the same value, now one shimmer;
and StoryInteractionsPopup was the only one not consulting the theme for
MenuFlyoutItemBackgroundPointerOver, so it now matches the other six rather than
always using the six percent white fallback.

Shapes are params, since two call sites pass a fixed pair and the rest pass an
array that is forwarded without copying. That makes a zero-shape call
expressible, which is worth guarding anyway: the loop-driven callers already
reach it whenever their row count is zero, and an empty group clips everything
away, attaching a skeleton that renders as nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20510 68
UnigramDev/Unigram/develop • c883cf7 • 1 files, +72/-3
Queue call transitions instead of blocking on the system call

TransitionToRequestingOrRinging blocked on InitializeSystemCallAsync, which
awaits the WinRT call reservation. VoipCoordinator.Handle calls Update from
inside its _activeLock on the TdReceive thread, and the VoipCall constructor
reaches the same transition, so the lock was held for the whole reservation —
including RequestNewIncomingCall and its 120 second ringing timeout. The UI
thread takes that lock through VoipCoordinator.ActiveCall, read from MainPage
and from the CallAccept and CallReject shortcuts, so it froze while a call was
being set up.

Awaiting alone would have introduced a worse problem. The block was also
ordering: a discard arriving while the reservation was in flight would reach
DisposeImpl with _systemCall still null, so nothing released it, and the
reservation completing afterwards would leave Windows showing an incoming call
that could no longer be ended.

Update now enqueues and returns, and a single pump applies transitions one at a
time in the order TDLib reported them. That keeps the ordering the block
provided while holding _activeLock only until the first await. The failure
handling matters: the catch sits inside the drain loop so one bad transition
cannot strand the rest, and _transitioning is cleared on the only exit, since a
call that stops draining would never reach Discarded.

UpdateImpl is otherwise the previous body unchanged, including its unlocked
read of _state, which races with OnStateUpdated and is left for its own change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 2180a5e • 1 files, +68/-19
Reserve the group call system call outside the constructor

All three VoipGroupCall constructors blocked on InitializeSystemCallAsync, and
VoipCoordinator runs each of them inside its _activeLock. The UI thread takes
that lock through VoipCoordinator.ActiveCall, read from MainPage and from
ChatGroupCallHeader, so it froze for the length of the reservation. The
ThreadPool.QueueUserWorkItem already wrapping those constructions kept the block
off the UI thread but did nothing about the lock.

Constructors cannot await, so the tail of each one moves into JoinAsync or
JoinConferenceAsync, started by the constructor and running after it returns.
The lock is then held only for field initialization. Ordering within the tail is
unchanged: reserve, create the window, then rejoin.

Leaving before the reservation completes needs handling that blocking made
unnecessary. Dispose would run with _systemCall still null, release nothing, and
the reservation completing afterwards would leave Windows holding a call that
can no longer be ended. Both paths check _isClosed once they have it and release
it themselves. _isClosed becomes volatile, since it is now read after an await
on a different thread from the one that sets it.

Dispose's system call teardown is extracted to DisposeSystemCall so the normal
and abandoned paths release it identically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20509 73
UnigramDev/Unigram/develop • a7f0db0 • 1 files, +34/-26
Honour requestedMinSide for every format in GetPreviewBitmapAsync

The method asked the decoder for its own BitmapPixelFormat, which
SoftwareBitmapSource accepts only when it happens to be Bgra8. The guard was
therefore testing the input rather than the output, and everything else fell
through to a BitmapImage decoded at full size, dropping requestedMinSide on the
path where it matters most.

Requesting Bgra8 premultiplied directly lets the decoder convert, which removes
the reason for the branch. One path, always the format SoftwareBitmapSource
needs, always bounded.

SoftwareBitmapSource holds a single frame, so an animated GIF would come back
static. Nothing reaches this with a GIF today, since StorageMedia previews
photos through a BitmapImage and only calls the overload above for video; the
summary records what a future caller would need.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 8700dde • 9 files, +27/-36
Update nuget packages

UnigramDev/Unigram/develop • ec916c0 • 3 files, +3/-1
Update round font

UnigramDev/Unigram/develop • 3be5e09 • 2 files, +3/-3
Fix ephemeral messages icon

UnigramDev/Unigram/develop • af506e6 • 2 files, +4/-4
Update property name

UnigramDev/Unigram/develop • e8560fb • 1 files, +1/-1
Update MicroTeX

UnigramDev/Unigram/develop • ce8637e • 5 files, +72/-7
New unsupported message template

#unigram
  • 🫡 2
Post #20508 71
UnigramDev/Unigram/develop • ba4ca6b • 1 files, +54/-18
Fix resource ownership and leaks in DrawStrokes

DrawStrokes is public, took a CanvasBitmap as a parameter and disposed it, so
any caller outside this file lost the bitmap it passed in. The caller now owns
both the bitmap it supplies and the render target it receives, and the summary
says so.

Nothing was scoped, so an exception between the two CanvasRenderTarget
constructions and the final dispose leaked all three objects. The body moves to
a private overload, leaving the public one to own the targets: the overlay is a
using and the returned target is disposed on the way out of a catch.

DrawStrokesAsync(SoftwareBitmap) leaked the InMemoryRandomAccessStream it
returns when SaveAsync threw. DrawStrokesAsync(StorageFile) relied on
DrawStrokes disposing the bitmap before the file was reopened for writing,
since it is loaded from that same path; the release is now explicit rather than
a side effect, and scoped to keep that order.

canvas1 and canvas2 become overlay and target.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 532b8cf • 1 files, +20/-12
Drop dead parameters and stale docs from ImageHelper

CropAsync took a quality parameter that nothing read: the property set it was
written for is commented out. No caller passed it, and none passes more than
five positional arguments, so removing it does not disturb them.

CropAsync also took trimStart and never forwarded it to OpenReadAsync, so a
trimmed video would have been cropped at position zero. ScaleAsync already
forwards its own; this one now does too. No caller passes it yet, so nothing
changes today.

The doc block above ScaleAsync described a quality parameter the method has
never had, and omitted the ones it does. Both commented-out property sets
referred to that parameter by name.

RotateArea computed width - (width - area.X), which is area.X, through an
intermediate Point.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • bfb6d0d • 1 files, +3/-1
Accept every video container in OpenReadAsync

The frame extraction path tested for the literal ".mp4", so .mov and .m4v took
the image branch and failed inside BitmapDecoder. Constants.VideoTypes is the
set EditMediaPopup already uses to decide whether a file is a video, and the two
disagreed.

Uses the existing HasExtension helper, which compares ordinal and
case-insensitive against the array without copying it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20507 62
UnigramDev/Unigram/develop • 27022ab • 1 files, +25/-6
Propagate video render failures out of ImageHelper

RenderSync answers whether it wrote a frame, and three call sites discarded it,
passing a BufferSurface that still held uninitialised memory to Encode or to a
WriteableBitmap.

Each needs a different answer. GetPreviewBitmapAsync returns null, which is
already its contract and which every caller substitutes a placeholder for.
CropAndPreviewAsync throws, because StorageMedia.Refresh recovers by falling
back to the unedited preview and does so from a catch, which a null would slip
past. OpenReadAsync throws, because callers pass the result straight to
BitmapDecoder and there is no null that does not simply move the failure; both
GenerationService and ImageCropper.SetSourceAsync catch it.

The blanket catch in GetPreviewBitmapAsync now logs. A codec the decoder cannot
handle was indistinguishable from a file with no frames.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • d4ac632 • 4 files, +208/-86
Remove per-frame allocations from message layout

Four allocations on paths that run for every message on every layout pass.

ReactionsPanel.ArrangeOverride built a List of rows and a List of rects per row
purely to centre them. A row is a contiguous run of children, complete as soon
as the next child does not fit, at which point its right edge is known, so each
run is now arranged in place. Both overrides also index Children rather than
enumerating it, since foreach over UIElementCollection allocates an
IEnumerator<UIElement> per pass.

LoadingTextBlock rebuilt its skeleton clip on every arrange: a native text
measurement, one D2D geometry per line, a group, a path, a path geometry and a
clip. It is now cached on the inputs it derives from.

ReplyMarkupInlinePanel rebuilt the rect buffers it hands to the native clip
builder, plus the clip itself, on every arrange. The buffers are reused and the
rects compared in place, so the clip is rebuilt only when one moves.

Discern gains an IList<UnreadReaction> overload over a shared core, so
ReactionsPanel no longer projects through Select on a list that is usually
empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • a2c8668 • 5 files, +28/-7
Release chart geometries built inside the draw pass

DrawChart and DrawPickerChart called CanvasGeometry.CreatePath once per line on
every frame and never disposed the result, leaving the native D2D geometry to
the finalizer. Seven sites now go through DrawGeometry and FillGeometry on
BaseChartView, which wrap the geometry in a using. The drawing session consumes
it before the call returns, so nothing outlives the scope.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20506 66
UnigramDev/Unigram/develop • 7bb3a02 • 3 files, +390/-390
Update maximize icon

UnigramDev/Unigram/develop • a4f390f • 4 files, +140/-206
Untangle ImageHelper scaling and crop duplication

The "fit inside N" calculation was spelled out inline seven times. Replace it
with three named primitives — FitRatio, Fit and Clamp — so the difference
between a target and a ceiling is visible at the call site rather than implied
by a parameter named requestedMinSide that holds a maximum.

Drop both Scale overloads. They had no callers, and Scale(this Size, double)
was an exact signature match for SizeEx.Scale in Telegram.Controls, which
multiplies by a factor rather than fitting to a box. Which of the two a file
got depended only on the namespace it sat in.

CropAsync and CropAndPreviewAsync carried a copy each of the same 45 lines,
including the same TODO verbatim. Both now call ComputeCropTransform.

Fix the minimum-size branch, which took the smaller of the two ratios: that
brings the longer edge down to the floor and leaves the shorter one further
below it than it started, so a 100x400 crop with a minimum of 160 came back
40x160. No effect on the only live caller, whose crop is always square.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

UnigramDev/Unigram/develop • 59b9050 • 3 files, +34/-17
Fix HEVC 10-bit video hanging VideoAnimation

decode_frame gated on a whitelist of pixel formats before the swscale path was
considered, so yuv420p10le was rejected outright and every frame returned -1.
The whitelist describes what libyuv can convert unaided, not what is supported;
it now gates only that fast path, and anything else goes through the scaler.

The alignment test likewise only chooses swscale in preference to libyuv, so it
applies only when a libyuv path exists. Without one the scaler is the only way
to convert the frame, and the scaling path already handles an unaligned
destination through an intermediate buffer.

RenderSync then spun. has_decoded_frames is set as soon as a frame is received,
before conversion, which freezes the try budget; the read-EOF branch does not
reset it. With conversion failing on every frame the loop decoded the file end
to end, seeked back to zero and repeated with no exit condition. A failed
conversion now spends a try, which bounds the loop regardless of the format.

RenderSync returns Boolean rather than Int32. It only ever returned 1 or 0, and
both internal callers already treated the result as a boolean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20505 102
UnigramDev/Unigram/develop • 6ea41c1 • 1 files, +9/-1
Fix crash when the default audio device changes during playback (#3321)

OnDefaultAudioRenderDeviceChanged handed libvlc a pointer to a string that
had already been destroyed:

Set(libvlc_audio_output_set, winrt::to_string(args.Id()).c_str());

Set forwards its arguments into a lambda that Write queues for the player's
worker thread, and captures them by value — which for a const char* copies the
pointer, not the characters. The temporary std::string returned by to_string
dies at the end of that statement, so by the time the work item is dequeued
libvlc reads freed memory.

The crash lands in strcmp, called from module_exists by
libvlc_audio_output_set as it compares the device name against known module
names, which is exactly what reading a freed string looks like.

Own the string in the capture instead, matching the Write call sites that
already exist in this file.

This fires whenever the system's default audio render device changes while a
player is alive — headphones plugged in or removed, a Bluetooth device
connecting, a call starting — which is why it is common enough to matter
despite needing a device change to trigger. Reported by crash telemetry on
12.8.1; the code is unchanged on develop.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20504 109
UnigramDev/Unigram/crash-vlc-dangling-audio-device • 3bd0033 • 1 files, +9/-1
Fix crash when the default audio device changes during playback

OnDefaultAudioRenderDeviceChanged handed libvlc a pointer to a string that
had already been destroyed:

Set(libvlc_audio_output_set, winrt::to_string(args.Id()).c_str());

Set forwards its arguments into a lambda that Write queues for the player's
worker thread, and captures them by value — which for a const char* copies the
pointer, not the characters. The temporary std::string returned by to_string
dies at the end of that statement, so by the time the work item is dequeued
libvlc reads freed memory.

The crash lands in strcmp, called from module_exists by
libvlc_audio_output_set as it compares the device name against known module
names, which is exactly what reading a freed string looks like.

Own the string in the capture instead, matching the Write call sites that
already exist in this file.

This fires whenever the system's default audio render device changes while a
player is alive — headphones plugged in or removed, a Bluetooth device
connecting, a call starting — which is why it is common enough to matter
despite needing a device change to trigger. Reported by crash telemetry on
12.8.1; the code is unchanged on develop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 3
Post #20503 100
UnigramDev/Unigram/develop • 0d19263 • 1 files, +38/-2
Fix crash activating the app as a share target before its window is created (#3320)

InitializeFrame dereferenced WindowContext.Current unconditionally:

if (WindowContext.Current.Content == null)
{
WindowContext.Current.Content = CreateRootElement(e, WindowContext.Current);
}

Share target activation appears to race window creation: the view has a
Window, but OnWindowCreated has not run yet, so no WindowContext exists and
the app dies with a NullReferenceException before it has any content.

Its only caller already allows for this — it tests WindowContext.Current?.Content
— so the null-conditional makes a missing context indistinguishable from
missing content, and InitializeFrame is called precisely when there is nothing
to dereference.

Make CreateWindowWrapper idempotent, and build the context early when
activation gets there first.

The idempotence is the load-bearing half. WindowContext's constructor assigns
the thread-static Current, so constructing a second one for a view that
already has one replaces it and silently orphans whatever was attached to the
first — including the frame. Creating the context during activation is only
safe because the OnWindowCreated that follows now reuses it instead of
replacing it. It is compared by window rather than assumed, and a context
belonging to a different window is still replaced, as before.

Logging is added on each path — reusing, creating, replacing, activating
early, and activating with no window at all — since this is a race that only
shows up in the field and the log tail is the only way to see which way it
went.

Reported by crash telemetry on 12.8.1, all of it through OnShareTargetActivated,
and the code is unchanged on develop.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20502 111
UnigramDev/Unigram/crash-sharetarget-null-window • e30f8e4 • 1 files, +38/-2
Fix crash activating the app as a share target before its window is created

InitializeFrame dereferenced WindowContext.Current unconditionally:

if (WindowContext.Current.Content == null)
{
WindowContext.Current.Content = CreateRootElement(e, WindowContext.Current);
}

Share target activation appears to race window creation: the view has a
Window, but OnWindowCreated has not run yet, so no WindowContext exists and
the app dies with a NullReferenceException before it has any content.

Its only caller already allows for this — it tests WindowContext.Current?.Content
— so the null-conditional makes a missing context indistinguishable from
missing content, and InitializeFrame is called precisely when there is nothing
to dereference.

Make CreateWindowWrapper idempotent, and build the context early when
activation gets there first.

The idempotence is the load-bearing half. WindowContext's constructor assigns
the thread-static Current, so constructing a second one for a view that
already has one replaces it and silently orphans whatever was attached to the
first — including the frame. Creating the context during activation is only
safe because the OnWindowCreated that follows now reuses it instead of
replacing it. It is compared by window rather than assumed, and a context
belonging to a different window is still replaced, as before.

Logging is added on each path — reusing, creating, replacing, activating
early, and activating with no window at all — since this is a race that only
shows up in the field and the log tail is the only way to see which way it
went.

Reported by crash telemetry on 12.8.1, all of it through OnShareTargetActivated,
and the code is unchanged on develop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20501 146
telegramdesktop/tdesktop/dev • 8e18cb7 • 1 files, +1/-0
Work around bugged D-Bus cmake config

It overrides pkg-config search paths but never restores them leading to pipewire being not found, disable the find_package call so that openal falls back to pkg-config directly

#tdesktop
  • 🫡 3
Post #20500 175
UnigramDev/Unigram/crash-sharetarget-null-window • 235fc66 • 1 files, +19/-2
Fix crash activating the app as a share target without a window context

InitializeFrame dereferenced WindowContext.Current unconditionally:

if (WindowContext.Current.Content == null)
{
WindowContext.Current.Content = CreateRootElement(e, WindowContext.Current);
}

WindowContext._current is [ThreadStatic]. It is assigned by the constructor,
which OnWindowCreated calls, and cleared again in OnShutdownCompleted when the
view's dispatcher shuts down. An activation arriving on a view that has been
through that shutdown therefore finds no context, and the app dies with a
NullReferenceException before it has a window.

Its only caller already allows for exactly this:

if (WindowContext.Current?.Content == null)
{
InitializeFrame(e);
}

The null-conditional makes a missing context indistinguishable from missing
content, so the branch is taken and InitializeFrame is called precisely when
there is nothing to dereference.

Build the context instead of assuming one. That is what OnWindowCreated would
have done, and it leaves the frame actually initialized rather than merely not
crashing, so the activation still gets a usable window. Where there is no
Window.Current either, there is nothing to build against; log and return.

Reported by crash telemetry on 12.8.1, all of it through OnShareTargetActivated,
and the code is unchanged on develop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20499 142
UnigramDev/Unigram/crash-autocomplete-template-mismatch • 381ea2d • 1 files, +24/-14
Fix crash populating autocomplete rows from a mismatched template

Autocomplete_ContainerContentChanging walked the container's visual tree on
the assumption that it matches args.Item:

var content = args.ItemContainer.ContentTemplateRoot as Grid;
var title = content.Children[1] as TextBlock;
var description = title.Inlines[1] as Run;
...
description.Text = ...

The list uses ItemTemplateSelector, so containers are recycled across item
types that have different templates, and ContentTemplateRoot can still be the
previous type's tree when this fires. Every step of that walk is an `as` cast
whose result is dereferenced immediately, so a mismatch is a
NullReferenceException in an event handler — fatal, not caught anywhere.

Reported by crash telemetry on 12.8.2, landing on the QuickReplyShortcut
branch. args.InRecycleQueue was already handled; this is the other half of the
recycling problem, where the container is live but not yet re-templated.

Match the expected shape and bail out when it isn't there, rather than
indexing into whatever tree happens to be present. Applied to the reported
branch and to the User branch, which is structurally identical and has the
same latent fault.

The remaining branches index container children the same way and share the
pattern, but have no reported crashes; leaving them for now to keep the change
reviewable rather than rewriting the whole handler.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20498 117
UnigramDev/Unigram/develop • 6404539 • 1 files, +15/-6
Fix crash opening the context menu on a partially selected message (#3317)

Message_ContextRequested built a MessageQuote straight from the selection and
immediately dereferenced it:

quote = new MessageQuote
{
Quote = parent.GetSelectedSourceText(out selectionStart),
...
};
selectionEnd = selectionStart + quote.Quote.Text.Length;

MessageSelector.HasSelection only reports that a selection is currently shown.
It is a plain flag, tracked separately from the ranges the text actually comes
from, so it can be true while GetSelectedSourceText returns null — when there
are no selected ranges, when the range collapses to nothing in source offsets,
or when the underlying block no longer has source text (GetSourceText returns
null for either of the last two). The result was a NullReferenceException out
of an async void handler, which is unhandled and takes the app down.

Reported by crash telemetry on 12.8.2.

Take the selected text first and only build the quote when there is one.
Everything downstream already treats a null quote as "no quote" — the very
next block reads `if (quote != null && MessageQuote_Loaded(...))` and falls
back to a plain reply — so leaving it unset is the behaviour the caller
already expects.

This only makes the call site agree with what the API can return; the flag and
the ranges are still tracked separately in TextSelectionManager, which is worth
revisiting on its own.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Post #20497 126
UnigramDev/Unigram/develop • b844676 • 1 files, +49/-5
Fix crash when MessageSelector loads before its content is set (#3316)

MessageSelector.OnLoaded built the TextSelectionManager unconditionally:

_textSelectionManager ??= new TextSelectionManager(this, ContentTemplateRoot);

TextSelectionManager's constructor rejects a null root, so whenever a
container was connected before it had been given content, the constructor
threw ArgumentNullException out of a Loaded handler, which is unhandled and
takes the app down.

Reported by crash telemetry on 12.8.2 ("Value cannot be null. Parameter
name: root"). The reported log tails show it under heavy UI churn — chat
navigation with popups opening — which is when layout is most likely to lag
behind connection.

Attach whenever a content element is actually present instead: on load, and
again from OnContentChanged whenever the content itself changes. The control
is always handed a UIElement directly and is never initialized through a
ContentTemplate, so Content is the element to attach to and ContentTemplateRoot
was the wrong property to read in the first place.

OnContentChanged detaches first. The manager's pointer handlers live on the
previous content element, so they have to come off before attaching to the
new one, or they outlive the element they were added to and the manager keeps
reporting selection for content that is no longer displayed.

EnsureTextSelectionManager also checks IsConnected. Only OnUnloaded and
OnContentChanged detach the manager, so attaching while disconnected would
leave the pointer handlers on the content permanently and, through them, root
the control for the rest of the session.

The four selection accessors dereferenced the manager unconditionally, which
would have turned this window into a NullReferenceException instead; they are
now null-safe.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

#unigram
  • 🫡 2
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →