Skip to content

Conversation

berrange
Copy link
Owner

@berrange berrange commented Apr 24, 2025

As defined by:

https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#open-h-264-encoding

The noVNC HTML application recently added support for this encoding. There is
also an open pull request to add audio support to noVNC:

novnc/noVNC#1952

With that in place, the web based VNC console is good enough to display
a VM showing a video with reasonable bandwidth.

Possible improvements:

  • Dynamic switching to/from H264 mode at high change rates
  • do not compute all rects in vnc_update_client to reduce CPU load

We may also extend the RFB Audio protocol with "opus" encoding, because uncompressed
audio need too much bandwidth.

Summary by Sourcery

Add H.264 video encoding support for VNC using GStreamer, enabling more efficient video streaming over VNC connections

New Features:

  • Implement H.264 video encoding for VNC using multiple GStreamer encoders
  • Add dynamic encoder selection with support for nvh264enc, vaapih264enc, x264enc, and openh264enc
  • Introduce configuration option to enable/disable H.264 encoding

Enhancements:

  • Optimize VNC refresh mechanism to support H.264 encoding
  • Add support for keeping dirty frames for smoother video transmission
  • Implement flexible encoder initialization and context management

Build:

  • Add GStreamer as an optional build dependency
  • Update meson build configuration to support H.264 encoding

CI:

  • Add GStreamer support to build options and configuration scripts

Summary by CodeRabbit

  • New Features

    • Added optional H.264 video encoding support for VNC using GStreamer, improving video streaming performance and efficiency.
    • Introduced a new build option to enable or disable GStreamer-based H.264 encoding for VNC.
    • Added a VNC server option to configure H.264 encoder selection or disable H.264 support.
    • Enhanced VNC client negotiation and update logic to support H.264 encoding, including optimized update scheduling.
  • Chores

    • Updated build scripts and help documentation to reflect new GStreamer and H.264 VNC options.

stefanhaRH and others added 30 commits March 13, 2025 17:57
Allow virtio-scsi virtqueues to be assigned to different IOThreads. This
makes it possible to take advantage of host multi-queue block layer
scalability by assigning virtqueues that have affinity with vCPUs to
different IOThreads that have affinity with host CPUs. The same feature
was introduced for virtio-blk in the past:
https://developers.redhat.com/articles/2024/09/05/scaling-virtio-blk-disk-io-iothread-virtqueue-mapping

Here are fio randread 4k iodepth=64 results from a 4 vCPU guest with an
Intel P4800X SSD:
iothreads IOPS
------------------------------
1         189576
2         312698
4         346744

Signed-off-by: Stefan Hajnoczi <[email protected]>
Message-ID: <[email protected]>
Tested-by: Peter Krempa <[email protected]>
[kwolf: Updated 051 output, virtio-scsi can now use any iothread]
Reviewed-by: Kevin Wolf <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
Previously the ctrl virtqueue was handled in the AioContext where SCSI
requests are processed. When IOThread Virtqueue Mapping was added things
become more complicated because SCSI requests could run in other
AioContexts.

Simplify by handling the ctrl virtqueue in the main loop where reset
operations can be performed. Note that BHs are still used canceling SCSI
requests in their AioContexts but at least the mean loop activity
doesn't need BHs anymore.

Signed-off-by: Stefan Hajnoczi <[email protected]>
Message-ID: <[email protected]>
Tested-by: Peter Krempa <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
Peter Krempa and Kevin Wolf observed that iothread-vq-mapping is
confusing to use because the control and event virtqueues have a fixed
location before the command virtqueues but need to be treated
differently.

Only expose the command virtqueues via iothread-vq-mapping so that the
command-line parameter is intuitive: it controls where SCSI requests are
processed.

The control virtqueue needs to be hardcoded to the main loop thread for
technical reasons anyway. Kevin also pointed out that it's better to
place the event virtqueue in the main loop thread since its no poll
behavior would prevent polling if assigned to an IOThread.

This change is its own commit to avoid squashing the previous commit.

Suggested-by: Kevin Wolf <[email protected]>
Suggested-by: Peter Krempa <[email protected]>
Signed-off-by: Stefan Hajnoczi <[email protected]>
Message-ID: <[email protected]>
Tested-by: Peter Krempa <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
This tool converts a disk image to qcow2, writing the result directly
to stdout. This can be used for example to send the generated file
over the network.

This is equivalent to using qemu-img to convert a file to qcow2 and
then writing the result to stdout, with the difference that this tool
does not need to create this temporary qcow2 file and therefore does
not need any additional disk space.

Implementing this directly in qemu-img is not really an option because
it expects the output file to be seekable and it is also meant to be a
generic tool that supports all combinations of file formats and image
options. Instead, this tool can only produce qcow2 files with the
basic options, without compression, encryption or other features.

The input file is read twice. The first pass is used to determine
which clusters contain non-zero data and that information is used to
create the qcow2 header, refcount table and blocks, and L1 and L2
tables. After all that metadata is created then the second pass is
used to write the guest data.

By default qcow2-to-stdout.py expects the input to be a raw file, but
if qemu-storage-daemon is available then it can also be used to read
images in other formats. Alternatively the user can also run qemu-nbd
or qemu-storage-daemon manually instead.

Signed-off-by: Alberto Garcia <[email protected]>
Signed-off-by: Madeeha Javed <[email protected]>
Message-ID: <[email protected]>
Reviewed-by: Kevin Wolf <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
…into staging

* Various fixes for functional tests
* Fix the name of the "configs" directory in the documentation

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmfSjagRHHRodXRoQHJl
# ZGhhdC5jb20ACgkQLtnXdP5wLbWBmA//RhAHuF/fTmQagBsZPETXjU1g8ifw9aqm
# WPZcQEXyQFlqYYQZmtV7dk3aTGEw4kBDmm+SKTSQz1yUcBGptMl8xuWaxgdpcOw0
# Bqt+lYNgwGL9/OocCdNolU3+aVbETljr5l+rzbnwsTVIqGk63Qhmtwdupb8h1nfY
# 4vCXU+sY3BkvBF8HbV6Wb1aPtqC+iH/Ln8+yoKkC8UePD623dK58SsOVrhUQDfFr
# U/HUy4BZlHFCfGGmDVGBjHdEbOzQkLQ9N3ilsNSWcF87RPkWPft+qLs4RjDFW+oT
# oksXEFHcr8XQO03fwHBNTyv+NUfnrvDY8V+gl6C9ItQr58SZzse57caZKWrYppZ3
# l5iHoaLMV3juZFDNXNHkWHuveXi05+0V0UbZihzBeC4+zjNRyh3e1GuDoh5VoG8o
# XIb55RxU8eBG2/ulHZ71eAYrGpxO+tDdsdnak1coPFsU8HrC9QzRfywiAZe1Wwmx
# 5t5AHbZ7RdnxgStU1lWTUT2IDVSini4DKevt/FzhKkv1aD8NbhI/ooGDC0zbS6SU
# XK6PP2G5a5OnjQ904oRCQbnhrxFa5qNfryylvvreT2bVgX0BiE4pJ9JXdgQOMYlP
# kZERZZQcv3y6VVavAT67yeNKQpyb4HSHdTDQ2irgXP1UwHRpwLpKdqB1UhzNJ8m8
# k0faA8RXir4=
# =VtGZ
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 13 Mar 2025 15:47:52 HKT
# gpg:                using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg:                issuer "[email protected]"
# gpg: Good signature from "Thomas Huth <[email protected]>" [full]
# gpg:                 aka "Thomas Huth <[email protected]>" [full]
# gpg:                 aka "Thomas Huth <[email protected]>" [full]
# gpg:                 aka "Thomas Huth <[email protected]>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* tag 'pull-request-2025-03-13' of https://gitlab.com/thuth/qemu:
  tests/functional: skip vulkan test if missing vulkaninfo
  tests/functional/asset: Add AssetError exception class
  tests/functional/asset: Verify downloaded size
  tests/functional/asset: Fail assert fetch when retries are exceeded
  docs/system: Fix the information on how to run certain functional tests
  tests/functional: Bump up arm_replay timeout
  tests/functional: Require 'user' netdev for ppc64 e500 test
  docs: Rename default-configs to configs

Signed-off-by: Stefan Hajnoczi <[email protected]>
Block layer patches

- virtio-scsi: add iothread-vq-mapping parameter
- Improve writethrough performance
- Fix missing zero init in bdrv_snapshot_goto()
- Added scripts/qcow2-to-stdout.py
- Code cleanup and iotests fixes

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmfTDysRHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9Yz6A//asOl37zjbtf9pYjY/gliH859TQOppPGD
# LB9IIr+nTDME0wfUkCOlag+CeEYZwkeo2PF+XeopsyzlJeBOk4tL7AkY57XYe3lZ
# M5hlnNrn6l3gb6iioMg60pEKSMrpKprB16vT3nAtyN6aEXsm9TvtPkWPFTCFGVeK
# W74VCr7wuXbfdEJcOGd8WhB9ZHIgwoWYnoL41tvCoefW2yNaMA6X0TLn98toXzOi
# il50ZnnchTQngns5R+n+1R1Ma995t393D+CArQcYVRzxKGOs5p0y4otz4gCkMhdp
# GVL09R7Ge4TteSJ2myxlN/EjYOxmdoMrVDajr4xPdHBw12MKzgk8i82h4/Es/Q5o
# 3Npgx74+jDyqlICb/czTVM5KJINpyO80vO3N3WpYUOQGyTCcYgv7pIpy8pB2o6Te
# RPlv0W9bHVSSgThFFLQ0Ud8WRGJe1K/ar8bdmiWN08Wez1avENWaYmsv5zGnFL24
# vD6cNXMR4mF7mzyeWda/5hGKv75djVgX+ZfzvWNT3qgizD56JBOA3RdCRwBZJOJb
# TvJkfi5RGyaji9BfKVCYBL3/iDELJEVDW8jxvIIUrS0aPcTHpAQ5gTO7VAokreqZ
# 5Smll11eeoEgPPvNLw8ikmOGTWOMkJGrmExP2K1ApANq3kSbBSU4jroEr0BG9PZT
# 6Y0hUdtFSdU=
# =w2Ri
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 14 Mar 2025 01:00:27 HKT
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "[email protected]"
# gpg: Good signature from "Kevin Wolf <[email protected]>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (23 commits)
  scripts/qcow2-to-stdout.py: Add script to write qcow2 images to stdout
  virtio-scsi: only expose cmd vqs via iothread-vq-mapping
  virtio-scsi: handle ctrl virtqueue in main loop
  virtio-scsi: add iothread-vq-mapping parameter
  virtio: extract iothread-vq-mapping.h API
  virtio-blk: tidy up iothread_vq_mapping functions
  virtio-blk: extract cleanup_iothread_vq_mapping() function
  virtio-scsi: perform TMFs in appropriate AioContexts
  virtio-scsi: protect events_dropped field
  virtio-scsi: introduce event and ctrl virtqueue locks
  scsi: introduce requests_lock
  scsi: track per-SCSIRequest AioContext
  dma: use current AioContext for dma_blk_io()
  scsi-disk: drop unused SCSIDiskState->bh field
  iotests: Limit qsd-migrate to working formats
  aio-posix: Adjust polling time also for new handlers
  aio-posix: Separate AioPolledEvent per AioHandler
  aio-posix: Factor out adjust_polling_time()
  aio: Create AioPolledEvent
  block/io: Ignore FUA with cache.no-flush=on
  ...

Signed-off-by: Stefan Hajnoczi <[email protected]>
The description of feature @unstable is three paragraphs.  The second
and third became part of the description by accident in commit
9fb49da (qapi: Mark unstable QMP parts with feature 'unstable').

The second paragraph describes a defect in terms of the
implementation.  Fine, but doesn't belong into user-facing
documentation.  Turn it into a TODO section.

Rewrite everything else for clarity and completeness.

Signed-off-by: Markus Armbruster <[email protected]>
Message-ID: <[email protected]>
Acked-by: Alberto Garcia <[email protected]>
When using the annotations feature, type hints do not need to be
imported at runtime, only at type check time. Move type-check-only
imports into a conditional to reduce the number of imports needed at
runtime.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
Currently, only the definition name is stored in the tree metadata; but
the node property is confusingly called "fullname". Rectify this by
always storing the FQN in the tree metadata.

... While we're here, re-organize the code in preparation for namespace
support to make it a bit easier to add additional components of the
FQN. With this change, there is now extremely little code left that's
taken directly from the Python domain :)

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
This patch adds a namespace component to the "Fully Qualified Name", in
the form of "domain:module.name". As there are no namespace directives
or options yet, this component will simply be empty as of this patch.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
Akin to the :module: override option, the :namespace: options allows you
to forcibly override the contextual namespace associatied with a
definition.

We don't necessarily actually need this, but I felt compelled to stick
close to how the Python domain works that offers context overrides.

As of this commit, it is possible to add e.g. ":namespace: QMP" to any
QAPI directive to forcibly associate that definition with a given
namespace.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
Add a new directive that marks the beginning of a QAPI "namespace", for
example; "QMP", "QGA" or "QSD". This directive will associate all
subsequent QAPI directives in a document with the specified
namespace. This does not change the visual display of any of the
definitions or index entries, but does change the "Fully Qualified Name"
inside the QAPI domain's object table. This allows for two different
"namespaces" to define entities with otherwise identical names -- which
will come in handy for documenting both QEMU QMP and the QEMU Storage
Daemon.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
Add a :namespace: option to the qapi-doc directive, which inserts a
qapi:namespace directive into the start of the generated document. This,
in turn, associates all auto-generated definitions by this directive
with the specified namespace.

The source info for these generated lines are credited to the start of
the qapi-doc directive, which isn't precisely correct, but I wasn't sure
how to get it more accurate without some re-parsing shenanigans.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
This patch does three things:

1. Record the current namespace context in pending_xrefs so it can be
   used for link resolution later,
2. Pass that recorded namespace context to find_obj() when resolving a
   reference, and
3. Wildly and completely rewrite find_obj().

cross-reference support is expanded to tolerate the presence or absence
of either namespace or module, and to cope with the presence or absence
of contextual information for either.

References now work like this:

1. If the explicit reference target is recorded in the domain's object
   registry, we link to that target and stop looking. We do this lookup
   regardless of how fully qualified the target is, which allows direct
   references to modules (which don't have a module component to their
   names) or direct references to definitions that may or may not belong
   to a namespace or module.

2. If contextual information is available from qapi:namespace or
   qapi:module directives, try using those components to find a direct
   match to the implied target name.

3. If both prior lookups fail, generate a series of regular expressions
   looking for wildcard matches in order from most to least
   specific. Any explicitly provided components (namespace, module)
   *must* match exactly, but both contextual and entirely omitted
   components are allowed to differ from the search result. Note that if
   more than one result is found, Sphinx will emit a warning (a build
   error for QEMU) and list all of the candidate references.

The practical upshot is that in the large majority of cases, namespace
and module information is not required when creating simple `references`
to definitions from within the same context -- even when identical
definitions exist in other contexts.

Even when using simple `references` from elsewhere in the QEMU
documentation manual, explicit namespace info is not required if there
is only one definition by that name.

Disambiguation *will* be required from outside of the QAPI documentation
when referencing e.g. block-core definitions, which are shared between
QEMU QMP and the QEMU Storage Daemon. In that case, there are two
options:

A: References can be made partially or fully explicit,
   e.g. `QMP:block-dirty-bitmap-add` will link to the QEMU version of
   the definition, while `QSD:block-dirty-bitmap-add` would link to the
   QSD version.

B: If all of the references in a document are intended to go to the same
   place, you can insert a "qapi:namespace:: QMP" directive to influence
   the fuzzy-searching for later references.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
[Commit message typo fixed]
Signed-off-by: Markus Armbruster <[email protected]>
Generate an index-per-namespace for the QAPI domain. Due to a limitation
with Sphinx's architecture, these indices must be defined during setup
time and cannot be dynamically created on-demand when a namespace
directive is encountered.

Owing to that limitation, add a configuration value to conf.py that
specifies which QAPI namespaces we'll generate indices for.

Indices will be named after their namespace, e.g. the "QMP" namespace
will generate to "qapi-qmp-index.html" and can be referenced using
`qapi-qmp-index`.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
This also creates the qapi-qmp-index.html index and cross-reference
target.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
Before we enable the QGA and QSD namespaces, we need to disambiguate
some of the references that would become ambiguous as a result!

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
This also creates the `qapi-qsd-index` and `qapi-qga-index` QMP indices.

Signed-off-by: John Snow <[email protected]>
Message-ID: <[email protected]>
Acked-by: Markus Armbruster <[email protected]>
Signed-off-by: Markus Armbruster <[email protected]>
The A32_BANKED_REG_{GET,SET} macros are only used inside target/arm;
move their definitions to cpregs.h. There's no need to have them
defined in all the code that includes cpu.h.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
We would like to move arm_el_is_aa64() to internals.h; however, it is
used by access_secure_reg().  Make that function not be inline, so
that it can stay in cpu.h.

access_secure_reg() is used only in two places:
 * in hflags.c
 * in the user-mode arm emulators, to decide whether to store
   the TLS value in the secure or non-secure banked field

The second of these is not on a super-hot path that would care about
the inlining (and incidentally will always use the NS banked field
because our user-mode CPUs never set ARM_FEATURE_EL3); put the
definition of access_secure_reg() in hflags.c, near its only use
inside target/arm.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
At the top of linux-user/aarch64/cpu_loop.c we define a set of
macros for reading and writing data and code words, but we never
use these macros. Delete them.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
In linux-user/arm/cpu_loop.c we define a full set of get/put
macros for both code and data (since the endianness handling
is different between the two). However the only one we actually
use is get_user_code_u32(). Remove the rest.

We leave a comment noting how data-side accesses should be handled
for big-endian, because that's a subtle point and we just removed the
macros that were effectively documenting it.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
The arm_cpu_data_is_big_endian() and related functions are now used
only in target/arm; they can be moved to internals.h.

The motivation here is that we would like to move arm_current_el()
to internals.h.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
The functions arm_current_el() and arm_el_is_aa64() are used only in
target/arm and in hw/intc/arm_gicv3_cpuif.c.  They're functions that
query internal state of the CPU.  Move them out of cpu.h and into
internals.h.

This means we need to include internals.h in arm_gicv3_cpuif.c, but
this is justifiable because that file is implementing the GICv3 CPU
interface, which really is part of the CPU proper; we just ended up
implementing it in code in hw/intc/ for historical reasons.

The motivation for this move is that we'd like to change
arm_el_is_aa64() to add a condition that uses cpu_isar_feature();
but we don't want to include cpu-features.h in cpu.h.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
…AArch32

The definition of SCR_EL3.RW says that its effective value is 1 if:
 - EL2 is implemented and does not support AArch32, and SCR_EL3.NS is 1
 - the effective value of SCR_EL3.{EEL2,NS} is {1,0} (i.e. we are
   Secure and Secure EL2 is disabled)

We implement the second of these in arm_el_is_aa64(), but forgot the
first.

Provide a new function arm_scr_rw_eff() to return the effective
value of SCR_EL3.RW, and use it in arm_el_is_aa64() and the other
places that currently look directly at the bit value.

(scr_write() enforces that the RW bit is RAO/WI if neither EL1 nor
EL2 have AArch32 support, but if EL1 does but EL2 does not then the
bit must still be writeable.)

This will mean that if code at EL3 attempts to perform an exception
return to AArch32 EL2 when EL2 is AArch64-only we will correctly
handle this as an illegal exception return: it will be caught by the
"return to an EL which is configured for a different register width"
check in HELPER(exception_return).

We do already have some CPU types which don't implement AArch32
above EL0, so this is technically a bug; it doesn't seem worth
backporting to stable because no sensible guest code will be
deliberately attempting to set the RW bit to a value corresponding
to an unimplemented execution state and then checking that we
did the right thing.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
Define the cpr_is_incoming helper, to be used in several cpr fix patches.

Signed-off-by: Steve Sistare <[email protected]>
Reviewed-by: Peter Xu <[email protected]>
Reviewed-by: Fabiano Rosas <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Fabiano Rosas <[email protected]>
During normal migration, new QEMU creates and initializes memory regions,
then loads the preserved contents of the region from vmstate.

During CPR, memory regions are preserved in place, then the realize
method initializes the regions contents, losing the old contents.  To
fix, skip the re-init during CPR.

Signed-off-by: Steve Sistare <[email protected]>
Reviewed-by: Fabiano Rosas <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Fabiano Rosas <[email protected]>
During normal migration, new QEMU creates and initializes memory regions,
then loads the preserved contents of the region from vmstate.

During CPR, memory regions are preserved in place, then the realize
method initializes the regions contents, losing the old contents.  To
fix, skip the re-init during CPR.

Signed-off-by: Steve Sistare <[email protected]>
Reviewed-by: Fabiano Rosas <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Fabiano Rosas <[email protected]>
During normal migration, new QEMU creates and initializes memory regions,
then loads the preserved contents of the region from vmstate.

During CPR, memory regions are preserved in place, then the realize
method initializes the regions contents, losing the old contents.  To
fix, skip writes to the qxl memory regions during CPR load.

Reported-by: [email protected]
Tested-by: [email protected]
Signed-off-by: Steve Sistare <[email protected]>
Reviewed-by: Fabiano Rosas <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Fabiano Rosas <[email protected]>
When EL1 doesn't support AArch32, the HCR_EL2.RW bit is supposed to
be RAO/WI. Enforce the RAO/WI behaviour.

Note that we handle "reset value should honour RES1 bits" in the same
way that SCR_EL3 does, via a reset function.

We do already have some CPU types which don't implement AArch32
above EL0, so this is technically a bug; it doesn't seem worth
backporting to stable because no sensible guest code will be
deliberately attempting to set the RW bit to a value corresponding
to an unimplemented execution state and then checking that we
did the right thing.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Richard Henderson <[email protected]>
stefanhaRH and others added 11 commits April 22, 2025 09:32
Signed-off-by: Stefan Hajnoczi <[email protected]>
GStreamer is required to implement H264 encoding for VNC. Please note
that QEMU already depends on this library when you enable Spice.

Signed-off-by: Dietmar Maurer <[email protected]>
This patch implements H264 support for VNC. The RFB protocol
extension is defined in:

https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#open-h-264-encoding

Currently the Gstreamer x264enc plugin (software encoder) is used
to encode the video stream.

The gstreamer pipe is:

appsrc -> videoconvert -> x264enc -> appsink

Note: videoconvert is required for RGBx to YUV420 conversion.

The code still use the VNC server framebuffer change detection,
and only encodes and sends video frames if there are changes.

Signed-off-by: Dietmar Maurer <[email protected]>
The H264 implementation only sends frames when it detects changes in
the server's framebuffer. This leads to artifacts when there are no
further changes, as the internal H264 encoder may still contain data.

This patch modifies the code to send a few additional frames in such
situations to flush the H264 encoder data.

Signed-off-by: Dietmar Maurer <[email protected]>
The search list is currently hardcoded to: ["x264enc", "openh264enc"]

x264enc: is probably the best available software encoder
openh264enc: lower quality, but available on more systems.

We restrict encoders to a known list because each encoder requires
fine tuning to get reasonable/usable results.

Signed-off-by: Dietmar Maurer <[email protected]>
Values can be 'on', 'off', or a space sparated list of
allowed gstreamer encoders.

- on: automatically select the encoder
- off: disbale h264
- encoder-list: select first available encoder from that list.

Signed-off-by: Dietmar Maurer <[email protected]>
Signed-off-by: Dietmar Maurer <[email protected]>
So that we can set --gst- options on the qemu command line.

Signed-off-by: Dietmar Maurer <[email protected]>
…ontext

Some encoders can hang indefinetly (i.e. nvh264enc) if
the pipeline is not stopped before it is destroyed
(Observed on Debian bookworm).

Signed-off-by: Dietmar Maurer <[email protected]>
Copy link

sourcery-ai bot commented Apr 24, 2025

Reviewer's Guide by Sourcery

This pull request implements the VNC H.264 encoding, enabling the server to stream video using the H.264 codec. It introduces new functions for H.264 initialization, encoding, and cleanup, and integrates with GStreamer for encoding. The changes also include a new VNC option to configure the H.264 encoder and modifications to the refresh logic to accommodate H.264 encoding requirements.

No diagrams generated as the changes look simple and do not need a visual representation.

File-Level Changes

Change Details Files
Implements the VNC H.264 encoding, allowing the server to send H.264 encoded video frames to the client.
  • Added VNC_ENCODING_H264 to the list of supported encodings.
  • Added a new vnc_h264_send_framebuffer_update function to handle H.264 encoding.
  • Added a new vnc_h264_clear function to release H.264 resources.
  • Added a new vnc_h264_encoder_init function to initialize the H.264 encoder.
  • Modified set_encodings to enable H.264 encoding if supported by the encoder list.
  • Modified vnc_disconnect_finish to clear H.264 resources on disconnect.
  • Modified vnc_refresh to conditionally keep the display dirty for H.264 encoding.
  • Modified vnc_worker_thread_loop to use H.264 encoding.
  • Added a new 'h264' option to the VNC options to configure the H.264 encoder.
  • Added gstreamer dependency to meson build file.
  • Added gstreamer support to vl.c.
  • Added gstreamer option to meson options file.
  • Added gstreamer support to ui/meson.build.
  • Created a new file ui/vnc-enc-h264.c to implement H.264 encoding.
ui/vnc.c
ui/vnc-jobs.c
ui/vnc.h
meson.build
system/vl.c
scripts/meson-buildoptions.sh
meson_options.txt
ui/meson.build
ui/vnc-enc-h264.c

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @berrange - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a configure option to control whether H.264 encoding is enabled at build time.
  • It might be worth exploring the use of a circular buffer to avoid allocating memory for each frame.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 2 issues found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

has_dirty = vnc_refresh_server_surface(vd);
vnc_unlock_display(vd);

QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting the H264-specific logic into a helper function to simplify the vnc_refresh loop and reduce nesting depth, which improves readability and maintainability without altering functionality..

Extract the H264‐specific logic into a helper function. For example, you could create a function that handles the “keep dirty” update and returns the effective client dirty flag. One way to do this is:

#ifdef CONFIG_GSTREAMER
static int h264_handle_dirty(VncState *vs, int client_dirty, bool *global_keep_dirty) {
    if (!vs->h264) {
        return client_dirty;
    }
    if (client_dirty) {
        vs->h264->keep_dirty = VNC_H264_KEEP_DIRTY;
    } else if (vs->h264->keep_dirty > 0) {
        client_dirty = 1;
        vs->h264->keep_dirty--;
    }
    if (vs->h264->keep_dirty > 0) {
        *global_keep_dirty = true;
    }
    return client_dirty;
}
#endif

Then, update your loop in vnc_refresh as follows:

QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
    int client_dirty = has_dirty;
#ifdef CONFIG_GSTREAMER
    client_dirty = h264_handle_dirty(vs, client_dirty, &keep_dirty);
#endif
    int count = vnc_update_client(vs, client_dirty);
    rects += count;

#ifdef CONFIG_GSTREAMER
    if (vs->h264 && !count && vs->h264->keep_dirty) {
        VncJob *job = vnc_job_new(vs);
        int height = pixman_image_get_height(vd->server);
        int width = pixman_image_get_width(vd->server);
        vs->job_update = vs->update;
        vs->update = VNC_STATE_UPDATE_NONE;
        vnc_job_add_rect(job, 0, 0, width, height);
        vnc_job_push(job);
    }
#endif
}

This refactoring keeps all functionality intact while reducing nesting in the critical loop.

vnc_write_u8(&vs, 0);
saved_offset = vs.output.offset;
vnc_write_u16(&vs, 0);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting the common rectangle update logic into a helper function to avoid code duplication between the H264 and non-H264 encoding paths, and to improve readability and maintainability of the code..

Consider extracting the common update logic into helper functions so that both branches reuse the same code where possible. For example, you can factor the rectangle handling into a small routine and then call it in the non‑H264 branch. One possible refactoring is:

static int process_frame_rectangles(VncState *vs, VncJob *job) {
    int n_rectangles = 0;
    VncRectEntry *entry, *tmp;

    QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
        int n;
        if (job->vs->ioc == NULL) {
            vnc_unlock_display(job->vs->vd);
            /* Copy persistent encoding data */
            vnc_async_encoding_end(job->vs, vs);
            return -1;  // signal disconnect
        }
        if (vnc_worker_clamp_rect(vs, job, &entry->rect)) {
            n = vnc_send_framebuffer_update(vs,
                                            entry->rect.x,
                                            entry->rect.y,
                                            entry->rect.w,
                                            entry->rect.h);
            if (n >= 0) {
                n_rectangles += n;
            }
        }
        g_free(entry);
    }
    return n_rectangles;
}

Then, in your worker thread loop, you can simplify the two branches:

vs.magic = VNC_MAGIC;
n_rectangles = 0;
vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
vnc_write_u8(&vs, 0);
saved_offset = vs.output.offset;
vnc_write_u16(&vs, 0);

vnc_lock_display(job->vs->vd);

if (vs.vnc_encoding == VNC_ENCODING_H264) {
    int width = pixman_image_get_width(vs.vd->server);
    int height = pixman_image_get_height(vs.vd->server);
    int n = vnc_send_framebuffer_update(&vs, 0, 0, width, height);
    if (n >= 0)
        n_rectangles += n;
    /* Free all rectangles since we are using full frame update */
    VncRectEntry *entry, *tmp;
    QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
        g_free(entry);
    }
} else {
    int n = process_frame_rectangles(&vs, job);
    if (n < 0)
        goto disconnected;
    n_rectangles += n;
}

trace_vnc_job_nrects(&vs, job, n_rectangles);
vnc_unlock_display(job->vs->vd);

/* Put n_rectangles at the beginning of the message */
vs.output.buffer[saved_offset]     = (n_rectangles >> 8) & 0xFF;
vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;

vnc_lock_output(job->vs);

This refactoring reduces duplicated rectangle processing logic while keeping all functionality intact.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suggestion doesn't remove any duplication, as the new funtion is only called in 1 place.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the context of the review comment and the subsequent response. Here's a thoughtful reply:

@berrange You make a fair point. The suggested refactoring might not significantly reduce code duplication if the extracted function is only called in one place.

The primary goal of my original suggestion was to improve code readability and maintainability, but if the proposed helper function doesn't provide clear benefits, it may indeed be unnecessary. In this case, keeping the current implementation might be more straightforward.

If you see opportunities for genuine code simplification or reduction of complexity in this section, I'm open to hearing your perspective. Sometimes, the most effective refactoring comes from the developers most familiar with the specific context and requirements of the code.

Would you be interested in discussing alternative approaches to improving the code structure or readability?

@berrange
Copy link
Owner Author

Hey @berrange - I've reviewed your changes - here's some feedback:

Overall Comments:

* Consider adding a configure option to control whether H.264 encoding is enabled at build time.

The patches already add a configure option

* It might be worth exploring the use of a circular buffer to avoid allocating memory for each frame.

Nope, this doesn't make sense.

Any other comments about correctness of the code ?

@berrange
Copy link
Owner Author

@CodiumAI-Agent /review

@CodiumAI-Agent
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Return type mismatch

vnc_h264_encoder_init is declared to return bool but returns -1 on failure, which converts to true, so error paths are not correctly reported.

encoder_name = get_available_encoder(vs->vd->h264_encoder_list);
if (encoder_name == NULL) {
    VNC_DEBUG("No H264 encoder available.\n");
    return -1;
}
Memory leak

The GstBuffer created by gst_buffer_new_wrapped_full is never unreffed or freed after pushing, causing a buffer leak each frame.

src_buffer = gst_buffer_new_wrapped_full(
    0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL);

g_signal_emit_by_name(
    vs->h264->source, "push-buffer", src_buffer, &flow_ret);
Uninitialized field

The VncH264.keep_dirty field is never initialized in the encoder init, leading to undefined behavior in the refresh logic.

/* Number of frames we send after the display is clean. */
#define VNC_H264_KEEP_DIRTY 10
typedef struct VncH264 {
    char *encoder_name;
    GstElement *pipeline, *source, *gst_encoder, *sink, *convert;
    size_t width;
    size_t height;
    guint keep_dirty;
    Notifier shutdown_notifier;
} VncH264;

@berrange
Copy link
Owner Author

@coderabbitai full review

Copy link

coderabbitai bot commented Apr 24, 2025

✅ Actions performed

Full review triggered.

Copy link

coderabbitai bot commented Apr 24, 2025

Walkthrough

This change set introduces optional H.264 video encoding for the VNC server using the GStreamer multimedia framework. The build system is updated to detect and configure GStreamer support, and a new build option is provided for enabling or disabling this feature. Integration with GStreamer is conditionally compiled and initialized at runtime. The VNC implementation is extended with new logic to negotiate, initialize, and utilize H.264 encoding for framebuffer updates, including support for encoder selection and handling of dirty regions. New source files and API declarations are added to support this functionality.

Changes

File(s) Change Summary
meson.build, meson_options.txt, ui/meson.build Added optional GStreamer dependency and build option; conditionally includes H.264 encoder source file for VNC when enabled.
scripts/meson-buildoptions.sh Added command-line flags and help for enabling/disabling GStreamer support in the build.
system/vl.c Conditionally includes and initializes GStreamer at program startup if enabled.
ui/vnc-enc-h264.c (new) Implements H.264 VNC encoder using GStreamer, including encoder selection, pipeline management, and framebuffer encoding logic.
ui/vnc-jobs.c Modifies VNC worker thread logic to handle H.264 encoding as a special case, sending full-frame updates and adjusting rectangle processing.
ui/vnc.c Integrates H.264 encoding into VNC client negotiation, framebuffer update sending, refresh scheduling, and display option parsing.
ui/vnc.h Adds data structures, constants, feature flags, and function declarations for H.264 encoding support in VNC.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant QEMU
    participant GStreamer
    participant VNC_Client

    User->>QEMU: Start QEMU with VNC + H264 option
    QEMU->>GStreamer: gst_init()
    QEMU->>VNC_Client: Negotiate encodings (includes H264)
    VNC_Client->>QEMU: Requests H264 encoding
    QEMU->>GStreamer: Setup encoder pipeline
    loop On framebuffer update
        QEMU->>GStreamer: Push raw frame data
        GStreamer-->>QEMU: Encoded H264 frame
        QEMU->>VNC_Client: Send H264 framebuffer update
    end
    User->>QEMU: Shutdown
    QEMU->>GStreamer: Cleanup pipeline
Loading

Poem

In the warren, code hops anew,
With GStreamer streams and H.264 in view.
VNC now sings a sharper tune,
Frames encoded, arriving soon!
Bunnies cheer for options bright,
And pipelines built just right—
Streaming dreams through the virtual night.
🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🔭 Outside diff range comments (1)
ui/vnc-jobs.c (1)

196-209: 🛠️ Refactor suggestion

Thread-safety risk: raw pointer to VncH264 is shared without ownership rules

vnc_async_encoding_start() / _end() merely copy the raw VncH264 * pointer between the I/O thread and the worker thread. While this works today, both threads may concurrently dereference the same GStreamer objects (e.g. if the main thread calls vnc_h264_clear() while the worker is still running) which is undefined behaviour and will crash inside GStreamer.

A low-cost fix is to guard vs->h264 with the existing output_mutex or hand the ownership exclusively to the worker for the duration of the job.

 /* vnc_async_encoding_start */
-    local->h264 = orig->h264;
+    WITH_QEMU_LOCK_GUARD(&orig->output_mutex) {
+        local->h264 = orig->h264;
+        if (local->h264) {
+            g_atomic_int_inc(&local->h264->refcnt);
+        }
+    }

…and symmetrically dec-ref in _end().

♻️ Duplicate comments (2)
ui/vnc-enc-h264.c (1)

274-287: ⚠️ Potential issue

Return value breaks contract with header

vnc_h264_encoder_init() is declared as bool but returns -1 on error.
Every caller will interpret this as “success”. Return false instead.

-        VNC_DEBUG("No H264 encoder available.\n");
-        return -1;
+        VNC_DEBUG("No H264 encoder available.\n");
+        return false;
...
-    return true;
+    return true;   /* unchanged */
ui/vnc.c (1)

3243-3256: Refactor H.264 “keep-dirty” handling into a helper (comment repeated)

This block inlines state management for keep_dirty, increasing the nesting
and cognitive load inside vnc_refresh(). A prior review already suggested
extracting it into a helper (see earlier discussion); the advice is still
valid and would make both paths (H.264 vs. non-H.264) easier to follow.

🧹 Nitpick comments (4)
meson.build (1)

1352-1357: Verify and refine the gstreamer dependency detection logic.

The condition if not get_option('gstreamer').auto() or have_block will probe for GStreamer whenever block‐device support is enabled, but H.264 encoding is actually tied to VNC, not block I/O. Consider tightening this to only detect GStreamer when the user explicitly requests it (get_option('gstreamer').enabled()) or when VNC is enabled (get_option('vnc').enabled()).

scripts/meson-buildoptions.sh (1)

232-232: Reposition the help entry to maintain alphabetical order.

The new gstreamer entry appears at the end of the list, but help options are grouped alphabetically. To keep the UI consistent, move:

  -- gstreamer       gstreamer support (H264 for VNC)

into the g section (e.g., between glusterfs and gnutls).

ui/vnc.h (1)

49-52: Avoid leaking GStreamer types to public headers

<gst/gst.h> is included unconditionally whenever CONFIG_GSTREAMER is set, propagating heavy GStreamer macros to every translation unit that includes vnc.h. Wrapping all GStreamer-specific structs in an opaque forward declaration keeps compile times down and removes dependency surprises for downstream code.

Also applies to: 191-194, 242-253

ui/vnc-enc-h264.c (1)

357-385: Defensive coding: replace tight assert()s with runtime checks

The function aborts the whole QEMU process if the server size ever differs
from client_width/client_height. A mis-behaving client should not be
able to crash the hypervisor; return -1 and fall back to RAW instead.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1da8f3a and 17f0414.

📒 Files selected for processing (9)
  • meson.build (3 hunks)
  • meson_options.txt (1 hunks)
  • scripts/meson-buildoptions.sh (2 hunks)
  • system/vl.c (2 hunks)
  • ui/meson.build (1 hunks)
  • ui/vnc-enc-h264.c (1 hunks)
  • ui/vnc-jobs.c (3 hunks)
  • ui/vnc.c (7 hunks)
  • ui/vnc.h (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
ui/vnc.c (3)
ui/vnc.h (6)
  • vnc_h264_send_framebuffer_update (655-655)
  • vs (72-72)
  • vs (74-74)
  • vs (76-80)
  • vnc_h264_clear (656-656)
  • vnc_h264_encoder_init (654-654)
ui/vnc-enc-h264.c (3)
  • vnc_h264_send_framebuffer_update (302-387)
  • vnc_h264_clear (389-401)
  • vnc_h264_encoder_init (274-296)
ui/vnc-jobs.c (3)
  • vnc_job_new (82-92)
  • vnc_job_add_rect (94-109)
  • vnc_job_push (111-121)
🪛 Cppcheck (2.10-2)
ui/vnc-enc-h264.c

[error] 48-48: syntax error

(syntaxError)

🔇 Additional comments (7)
meson_options.txt (1)

257-258: LGTM! The GStreamer option is correctly defined.

The new GStreamer option is properly defined as a feature type with an auto default value, which is consistent with other VNC-related options. The description clearly indicates its purpose for VNC H.264 encoding.

system/vl.c (2)

143-145: LGTM! Proper conditional inclusion of GStreamer headers.

The GStreamer header inclusion is correctly guarded with CONFIG_GSTREAMER preprocessor checks, ensuring it's only included when the feature is enabled.


2855-2857: LGTM! GStreamer initialization is correctly implemented.

The GStreamer initialization with gst_init(&argc, &argv) is properly guarded with CONFIG_GSTREAMER and placed early in the initialization sequence, which is important as it allows GStreamer to process any of its own command-line arguments.

ui/meson.build (1)

49-49: LGTM! Conditional addition of the H.264 encoder source.

The new source file vnc-enc-h264.c is correctly added to the VNC source set, conditionally included only when GStreamer is enabled. This follows the same pattern used for other conditional VNC features like SASL authentication.

meson.build (2)

2574-2575: Record GStreamer found status correctly.

Setting CONFIG_GSTREAMER to gstreamer.found() aligns with other feature flags. This will make the #ifdef CONFIG_GSTREAMER guard available in C code.


4848-4849: Include GStreamer in the configuration summary.

Adding {'gstreamer support': gstreamer} to summary_info follows the existing pattern for optional dependencies (e.g., zstd, qpl). This will print the detected GStreamer package or false if not found.

ui/vnc-enc-h264.c (1)

119-147: destroy_encoder_context() ignores NULL safety for partial init

If failure happens mid-initialisation some members may still be NULL.
gst_clear_object() already tolerates NULL, but gst_element_set_state
does not – guard the call:

if (h264->pipeline) {
    ...
}

Comment on lines +585 to +587
--enable-gstreamer) printf "%s" -Dgstreamer=enabled ;;
--disable-gstreamer) printf "%s" -Dgstreamer=disabled ;;
*) return 1 ;;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Regenerate this script instead of manual edits.

This file is auto‐generated by meson-buildoptions.py (“do not edit!”). Manual additions risk being overwritten. Please update meson-buildoptions.py (and/or meson_options.txt) to include gstreamer, then re-run the generator to produce these --enable-gstreamer/--disable-gstreamer entries.

Comment on lines 290 to 300
if (vs.vnc_encoding == VNC_ENCODING_H264) {
int width = pixman_image_get_width(vs.vd->server);
int height = pixman_image_get_height(vs.vd->server);
int n = vnc_send_framebuffer_update(&vs, 0, 0, width, height);
if (n >= 0) {
n_rectangles += n;
}
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
g_free(entry);
}
} else {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Possible disconnection race is no longer handled for H.264 path

In the legacy branch we bail out if job->vs->ioc == NULL to avoid writing to a dead socket, yet the new H.264 branch omits this check. If the client disappears between the first ioc check (line 262) and this point the encoder may still produce data that will never be sent and leak buffers.

At minimum mirror the early-exit pattern used below:

if (job->vs->ioc == NULL) {
    vnc_unlock_display(job->vs->vd);
    vnc_async_encoding_end(job->vs, &vs);
    goto disconnected;
}

Comment on lines 654 to 657
bool vnc_h264_encoder_init(VncState *vs);
int vnc_h264_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
void vnc_h264_clear(VncState *vs);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Public API returns bool – callers expect false, not -1

The declaration advertises a boolean result, but the implementation (ui/vnc-enc-h264.c) returns -1 on failure. In C this is equivalent to true, so error paths are silently treated as success. Please change the implementation to return false instead (and keep the success path returning true).

Comment on lines 345 to 355
src_buffer = gst_buffer_new_wrapped_full(
0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL);

g_signal_emit_by_name(
vs->h264->source, "push-buffer", src_buffer, &flow_ret);

if (flow_ret != GST_FLOW_OK) {
VNC_DEBUG("gst appsrc push buffer failed\n");
return -1;
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

src_buffer is never unreffed – memory leak per frame

gst_buffer_new_wrapped_full() adds a reference which must be released
after the push succeeds. Without gst_buffer_unref(src_buffer) the
reference count is never decremented, leaking one buffer every screen
refresh.

 g_signal_emit_by_name(
     vs->h264->source, "push-buffer", src_buffer, &flow_ret);
+gst_buffer_unref(src_buffer);   /* drop our reference */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
src_buffer = gst_buffer_new_wrapped_full(
0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL);
g_signal_emit_by_name(
vs->h264->source, "push-buffer", src_buffer, &flow_ret);
if (flow_ret != GST_FLOW_OK) {
VNC_DEBUG("gst appsrc push buffer failed\n");
return -1;
}
src_buffer = gst_buffer_new_wrapped_full(
0, src_data_ptr, src_data_size, 0, src_data_size, NULL, NULL);
g_signal_emit_by_name(
vs->h264->source, "push-buffer", src_buffer, &flow_ret);
gst_buffer_unref(src_buffer); /* drop our reference */
if (flow_ret != GST_FLOW_OK) {
VNC_DEBUG("gst appsrc push buffer failed\n");
return -1;
}

Comment on lines 2191 to 2199
#ifdef CONFIG_GSTREAMER
case VNC_ENCODING_H264:
if (vs->vd->h264_encoder_list != NULL) { /* if h264 is enabled */
if (vnc_h264_encoder_init(vs)) {
vnc_set_feature(vs, VNC_FEATURE_H264);
vs->vnc_encoding = enc;
}
}
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

vnc_h264_encoder_init() uses bool but returns -1 → error paths look like success

vnc_h264_encoder_init() is declared to return int/bool but its
implementation returns -1 on failure and true on success.
Because C treats every non-zero value as true, callers (like the block
below) treat the failure path as success and enable H.264 anyway.

-    if (encoder_name == NULL) {
-        VNC_DEBUG("No H264 encoder available.\n");
-        return -1;
+    if (!encoder_name) {
+        VNC_DEBUG("No H264 encoder available.\n");
+        return false;   /* ← failure */
     }
...
-    return true;

Update both the implementation and all call-sites (set_encodings(), etc.) to
treat false/0 as failure.
This prevents clients from negotiating a non-working H.264 stream.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 975 to 977
case VNC_ENCODING_H264:
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h);
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Guard H.264 case with CONFIG_GSTREAMER to avoid link-time breakage

vnc_h264_send_framebuffer_update() is only compiled when CONFIG_GSTREAMER
is defined (see ui/vnc-enc-h264.c).
When QEMU is built without GStreamer, the symbol is absent, and these
un-guarded lines will trigger an undefined-reference linker error.

+#ifdef CONFIG_GSTREAMER
     case VNC_ENCODING_H264:
         n = vnc_h264_send_framebuffer_update(vs, x, y, w, h);
         break;
+#endif

If you still want VNC_ENCODING_H264 numerically accepted when GStreamer is
disabled, fall back to VNC_ENCODING_RAW (or reject it) inside the #else.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case VNC_ENCODING_H264:
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h);
break;
#ifdef CONFIG_GSTREAMER
case VNC_ENCODING_H264:
n = vnc_h264_send_framebuffer_update(vs, x, y, w, h);
break;
#endif

Comment on lines 4207 to 4215
const char *h264_opt = qemu_opt_get(opts, "h264");
if (!strcmp(h264_opt, "off")) {
vd->h264_encoder_list = NULL; /* disable h264 */
} else if (!strcmp(h264_opt, "on")) {
vd->h264_encoder_list = ""; /* use default encoder list */
} else {
/* assume this is a list of endiers */
vd->h264_encoder_list = h264_opt;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

strcmp() on a possible NULL ‑ unchecked access can segfault

qemu_opt_get(opts, "h264") returns NULL when the option is omitted, but the
code immediately dereferences the pointer with strcmp().
Booting QEMU without an explicit h264= parameter will therefore crash.

const char *h264_opt = qemu_opt_get(opts, "h264");

/* Default: "on" when option is absent */
-if (!strcmp(h264_opt, "off")) {
+if (!h264_opt || !strcmp(h264_opt, "on")) {
+    vd->h264_encoder_list = "";          /* enable with default list */
+} else if (!strcmp(h264_opt, "off")) {
     vd->h264_encoder_list = NULL;        /* disable h264 */
-} else if  (!strcmp(h264_opt, "on")) {
-    vd->h264_encoder_list = "";          /* enable with default list */
 } else {
     /* assume this is a comma-separated encoder list */
     vd->h264_encoder_list = h264_opt;
 }

Add a unit/CLI test to ensure bare -vnc ...,h264 (or no parameter) no longer
crashes.

Committable suggestion skipped: line range outside the PR's diff.

@berrange berrange closed this May 16, 2025
berrange pushed a commit that referenced this pull request May 21, 2025
ASAN spotted a leaking string in machine_set_loadparm():

Direct leak of 9 byte(s) in 1 object(s) allocated from:
    #0 0x560ffb5bb379 in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
    #1 0x7f1aca926518 in g_malloc ../glib/gmem.c:106
    #2 0x7f1aca94113e in g_strdup ../glib/gstrfuncs.c:364
    #3 0x560ffc8afbf9 in qobject_input_type_str ../qapi/qobject-input-visitor.c:542:12
    #4 0x560ffc8a80ff in visit_type_str ../qapi/qapi-visit-core.c:349:10
    #5 0x560ffbe6053a in machine_set_loadparm ../hw/s390x/s390-virtio-ccw.c:802:10
    qemu#6 0x560ffc0c5e52 in object_property_set ../qom/object.c:1450:5
    qemu#7 0x560ffc0d4175 in object_property_set_qobject ../qom/qom-qobject.c:28:10
    qemu#8 0x560ffc0c6004 in object_property_set_str ../qom/object.c:1458:15
    qemu#9 0x560ffbe2ae60 in update_machine_ipl_properties ../hw/s390x/ipl.c:569:9
    qemu#10 0x560ffbe2aa65 in s390_ipl_update_diag308 ../hw/s390x/ipl.c:594:5
    qemu#11 0x560ffbdee132 in handle_diag_308 ../target/s390x/diag.c:147:9
    qemu#12 0x560ffbebb956 in helper_diag ../target/s390x/tcg/misc_helper.c:137:9
    qemu#13 0x7f1a3c51c730  (/memfd:tcg-jit (deleted)+0x39730)

Cc: [email protected]
Signed-off-by: Fabiano Rosas <[email protected]>
Message-ID: <[email protected]>
Fixes: 1fd396e ("s390x: Register TYPE_S390_CCW_MACHINE properties as class properties")
Reviewed-by: Thomas Huth <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Signed-off-by: Thomas Huth <[email protected]>
berrange pushed a commit that referenced this pull request Jul 15, 2025
ASAN spotted a leak of the memory used to hold the tmp_path:

Direct leak of 35 byte(s) in 1 object(s) allocated from:
    #0 0x55e29aa96da9 in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
    #1 0x7fe0cfb26518 in g_malloc ../glib/gmem.c:106
    #2 0x7fe0cfb4146e in g_strconcat ../glib/gstrfuncs.c:629
    #3 0x7fe0cfb0a78f in g_get_tmp_name ../glib/gfileutils.c:1742
    #4 0x7fe0cfb0b00b in g_file_open_tmp ../glib/gfileutils.c:1802
    #5 0x55e29ab53961 in test_ast2700_evb ../tests/qtest/ast2700-smc-test.c:20:10
    qemu#6 0x55e29ab53803 in main ../tests/qtest/ast2700-smc-test.c:65:5
    qemu#7 0x7fe0cf7bd24c in __libc_start_main ../csu/libc-start.c:308
    qemu#8 0x55e29a9f7759 in _start ../sysdeps/x86_64/start.S:120

Signed-off-by: Fabiano Rosas <[email protected]>
Reviewed-by: Jamin Lin <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
berrange pushed a commit that referenced this pull request Sep 8, 2025
In stm32f250_soc_initfn() we mostly use the standard pattern
for child objects of calling object_initialize_child(). However
for s->adc_irqs we call object_new() and then later qdev_realize(),
and we never unref the object on deinit. This causes a leak,
detected by ASAN on the device-introspect-test:

Indirect leak of 10 byte(s) in 1 object(s) allocated from:
    #0 0x5b9fc4789de3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-arm+0x21f1de3) (BuildId: 267a2619a026ed91c78a07b1eb2ef15381538efe)
    #1 0x740de3f28b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x740de3f3e4d8 in g_strdup (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x784d8) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #3 0x5b9fc70159e1 in g_strdup_inline /usr/include/glib-2.0/glib/gstrfuncs.h:321:10
    #4 0x5b9fc70159e1 in object_property_try_add /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1276:18
    #5 0x5b9fc7015f94 in object_property_add /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1294:12
    qemu#6 0x5b9fc701b900 in object_add_link_prop /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:2021:10
    qemu#7 0x5b9fc701b3fc in object_property_add_link /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:2037:12
    qemu#8 0x5b9fc4c299fb in qdev_init_gpio_out_named /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/gpio.c:90:9
    qemu#9 0x5b9fc4c29b26 in qdev_init_gpio_out /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/gpio.c:101:5
    qemu#10 0x5b9fc4c0f77a in or_irq_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/or-irq.c:70:5
    qemu#11 0x5b9fc70257e1 in object_init_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:428:9
    qemu#12 0x5b9fc700cd4b in object_initialize_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:570:5
    qemu#13 0x5b9fc700e66d in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:774:5
    qemu#14 0x5b9fc700e750 in object_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:789:12
    qemu#15 0x5b9fc68b2162 in stm32f205_soc_initfn /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/stm32f205_soc.c:69:26

Switch to using object_initialize_child() like all our
other child objects for this SoC object.

Cc: [email protected]
Fixes: b63041c ("STM32F205: Connect the ADC devices")
Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Message-id: [email protected]
berrange pushed a commit that referenced this pull request Sep 8, 2025
The serial-pci-multi device initializes an IRQ with qemu_init_irq()
in its instance_init function; however it never calls qemu_free_irq(),
so the init/deinit cycle has a memory leak, which ASAN catches
in the device-introspect-test:

Direct leak of 576 byte(s) in 6 object(s) allocated from:
    #0 0x626306ddade3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qem
u-system-arm+0x21f1de3) (BuildId: 52ece17287eba2d68e5be980e1856cd1f6be932f)
    #1 0x7756ade79b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1
eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x7756ade5b45a in g_hash_table_new_full (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4445a
) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #3 0x62630965da37 in object_initialize_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qem
u/build/arm-asan/../../qom/object.c:568:23
    #4 0x62630965d440 in object_initialize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/ar
m-asan/../../qom/object.c:578:5
    #5 0x626309653eeb in qemu_init_irq /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-as
an/../../hw/core/irq.c:48:5
    qemu#6 0x6263072370bb in multi_serial_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/char/serial-pci-multi.c:183:9

Use the new qemu_init_irq_child() function instead, so that the
IRQ object is automatically unreffed when the serial-pci
device is deinited.

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Message-ID: <[email protected]>
[PMD: Use "irq[*]" as child property name]
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
berrange pushed a commit that referenced this pull request Sep 8, 2025
The ICH9 PCI device uses qemu_init_irq() in its instance_init method,
but fails to clean it up in its uninit. This results in a leak,
detected by ASAN when running the device-introspect-test:

Direct leak of 96 byte(s) in 1 object(s) allocated from:
    #0 0x58f3b53ecde3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qem
u-system-arm+0x21f1de3) (BuildId: 8dcd38b1d76bd7bd44f905c38200f4cceafd7ca4)
    #1 0x72e446dd5b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1
eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x72e446db745a in g_hash_table_new_full (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4445a
) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #3 0x58f3b7c6fc67 in object_initialize_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qem
u/build/arm-asan/../../qom/object.c:568:23
    #4 0x58f3b7c6f670 in object_initialize /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/ar
m-asan/../../qom/object.c:578:5
    #5 0x58f3b7c6611b in qemu_init_irq /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/irq.c:48:5
    qemu#6 0x58f3b5c6e931 in pci_ich9_ahci_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/ide/ich.c:117:5

We could call qemu_free_irq() in pci_ich9_uninit(), but
since we have a method of initializing the IRQ that doesn't
need manual freeing, use that instead: qemu_init_irq_child().

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
berrange pushed a commit that referenced this pull request Sep 8, 2025
In pca9554_set_pin() we have a string property which we parse in
order to set some non-string fields in the device state.  So we call
visit_type_str(), passing it the address of the local variable
state_str.

visit_type_str() will allocate a new copy of the string; we
never free this string, so the result is a memory leak, detected
by ASAN during a "make check" run:

Direct leak of 5 byte(s) in 1 object(s) allocated from:
    #0 0x5d605212ede3 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-arm+0x21f1de3) (
BuildId: 3d5373c89317f58bfcd191a33988c7347714be14)
    #1 0x7f7edea57b09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b68282
9a6913cf682d75)
    #2 0x7f7edea6d4d8 in g_strdup (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x784d8) (BuildId: 1eb6131419edb83b2178b68282
9a6913cf682d75)
    #3 0x5d6055289a91 in g_strdup_inline /usr/include/glib-2.0/glib/gstrfuncs.h:321:10
    #4 0x5d6055289a91 in qobject_input_type_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qapi/qo
bject-input-visitor.c:542:12
    #5 0x5d605528479c in visit_type_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qapi/qapi-visit
-core.c:349:10
    qemu#6 0x5d60528bdd87 in pca9554_set_pin /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/gpio/pca9554.c:179:10
    qemu#7 0x5d60549bcbbb in object_property_set /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1450:5
    qemu#8 0x5d60549d2055 in object_property_set_qobject /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/qom-qobject.c:28:10
    qemu#9 0x5d60549bcdf1 in object_property_set_str /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:1458:15
    qemu#10 0x5d605439d077 in gb200nvl_bmc_i2c_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/aspeed.c:1267:5
    qemu#11 0x5d60543a3bbc in aspeed_machine_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/aspeed.c:493:9

Make the state_str g_autofree, so that we will always free
it, on both error-exit and success codepaths.

Cc: [email protected]
Fixes: de0c7d5 ("misc: Add a pca9554 GPIO device model")
Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Glenn Miles <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
berrange pushed a commit that referenced this pull request Sep 8, 2025
In the xnlx_dp_init() function we create the s->dpcd and
s->edid objects with qdev_new(); then in xlnx_dp_realize()
we realize the dpcd with qdev_realize() and the edid with
qdev_realize_and_unref().

This is inconsistent, and both ways result in a memory
leak for the instance_init -> deinit lifecycle tested
by device-introspect-test:

Indirect leak of 1968 byte(s) in 1 object(s) allocated from:
    #0 0x5aded4d54e23 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x24ffe23) (BuildId: 9f1e6c5
3fecd904ba5fc1f521d7da080a0e4103b)
    #1 0x71fbfac9bb09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x5aded7b9211c in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:767:15
    #3 0x5aded7b92240 in object_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:789:12
    #4 0x5aded7b773e4 in qdev_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/qdev.c:149:19
    #5 0x5aded54458be in xlnx_dp_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/display/xlnx_dp.c:1272:20

Direct leak of 344 byte(s) in 1 object(s) allocated from:
    #0 0x5aded4d54e23 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x24ffe23) (BuildId: 9f1e6c53fecd904ba5fc1f521d7da080a0e4103b)
    #1 0x71fbfac9bb09 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62b09) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x5aded7b9211c in object_new_with_type /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:767:15
    #3 0x5aded7b92240 in object_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:789:12
    #4 0x5aded7b773e4 in qdev_new /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/core/qdev.c:149:19
    #5 0x5aded5445a56 in xlnx_dp_init /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/display/xlnx_dp.c:1275:22

Instead, explicitly object_unref() after we have added the objects as
child properties of the device.  This means they will automatically
be freed when this device is deinited.  When we do this,
qdev_realize() is the correct way to realize them in
xlnx_dp_realize().

Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Francisco Iglesias <[email protected]>
Reviewed-by: Manos Pitsidianakis <[email protected]>
Reviewed-by: Edgar E. Iglesias <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
berrange pushed a commit that referenced this pull request Sep 8, 2025
When running the bios-tables-test under ASAN we see leaks like this:

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x5bc58579b00d in calloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x250400d) (BuildId: 2e27b63dc9ac45f522ced40a17c2a60cc32f1d38)
    #1 0x7b4ad90337b1 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x637b1) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #2 0x5bc5861826db in qmp_memory_device_list /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/mem/memory-device.c:307:34
    #3 0x5bc587a9edb6 in arm_load_dtb /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/arm/boot.c:656:15

Indirect leak of 28 byte(s) in 2 object(s) allocated from:
    #0 0x5bc58579ae23 in malloc (/mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/qemu-system-aarch64+0x2503e23) (BuildId: 2e27b63dc9ac45f522ced40a17c2a60cc32f1d38)
    #1 0x7b4ad6c8f947 in __vasprintf_internal libio/vasprintf.c:116:16
    #2 0x7b4ad9080a52 in g_vasprintf (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0xb0a52) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #3 0x7b4ad90515e4 in g_strdup_vprintf (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x815e4) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #4 0x7b4ad9051940 in g_strdup_printf (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x81940) (BuildId: 1eb6131419edb83b2178b682829a6913cf682d75)
    #5 0x5bc5885eb739 in object_get_canonical_path /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../qom/object.c:2123:19
    qemu#6 0x5bc58618dca8 in pc_dimm_md_fill_device_info /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/mem/pc-dimm.c:268:18
    qemu#7 0x5bc586182792 in qmp_memory_device_list /mnt/nvmedisk/linaro/qemu-from-laptop/qemu/build/arm-asan/../../hw/mem/memory-device.c:310:9

This happens because we declared the MemoryDeviceInfoList *md_list
with g_autofree, which will free the direct memory with g_free() but
doesn't free all the other data structures referenced by it.  Instead
what we want is to declare the pointer with g_autoptr(), which will
automatically call the qapi_free_MemoryDeviceInfoList() cleanup
function when the variable goes out of scope.

Fixes: 36bc78a ("hw/arm: add static NVDIMMs in device tree")
Signed-off-by: Peter Maydell <[email protected]>
Reviewed-by: Manos Pitsidianakis <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Message-ID: <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
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.