tests/realtek: Cover the storage error path that returned a freed GError

Deleting a print whose template is not in the sensor's storage makes the
driver fail its task SSM, which is the path that handed an already-freed
GError to fpi_device_delete_complete(). Reading the reported error is
therefore what the test is for.

No enrollment is involved: the test deserializes a stored realtek print
whose template is deliberately not on the device, so the recording needs
no finger presses and the capture stays at 90 packets.

Without the previous commit the test dies rather than fails:

  umockdev-run ... died with <Signals.SIGSEGV: 11>
  1/1 drivers+custom - libfprint:realtek-storage-errors FAIL

The duplicate-enrollment path reaches the same bug through
fp_enroll_ssm_done(), but capturing it needs two full enrollments and
some 1.07M packets of polling traffic, so it is left out here.
This commit is contained in:
Ge-org Brohammer
2026-08-28 15:19:30 +02:00
parent 26d38779e4
commit 3a41fa7ccc
4 changed files with 402 additions and 0 deletions
+1
View File
@@ -59,6 +59,7 @@ drivers_tests = {
'fpcmoc': {},
'realtek': {},
'realtek-5816': {},
'realtek-storage-errors': {},
'focaltech_moc': { 'timeout': 30 },
'focaltech_moc-6553': {},
'mafpmoc': {},
Binary file not shown.
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
# Deleting a print that is not in the sensor's storage makes the realtek driver
# fail its task SSM, which is the path that used to hand an already-freed GError
# to fpi_device_delete_complete(). Reading the reported error is therefore the
# point of this test: before the fix it read freed memory, and the GError was
# freed a second time when the GTask finalized.
#
# No enrollment is involved, so this needs no recorded finger presses: the print
# below is a stored realtek print, serialized, whose template is deliberately
# not on the device.
import base64
import traceback
import sys
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib
# Exit with error on any exception, included those happening in async callbacks
sys.excepthook = lambda *args: (traceback.print_exception(*args), sys.exit(1))
# A stored print for user 'testuser', right index finger, user id
# 'FP1-20260101-7-DEADBEEF-test'.
STORED_PRINT = base64.b64decode(
'RlAzAQAAAHJlYWx0ZWsAMAABB3Rlc3R1c2VyAABGUDEtMjAyNjAxMDEtNy1ERUFEQkVFRi10ZXN0AAAhSQsAAAAAAP9GUDEtMjAyNjAxMDEtNy1ERUFEQkVFRi10ZXN0ACh5YXkpAHZAOBoODA==')
ctx = GLib.main_context_default()
c = FPrint.Context()
c.enumerate()
devices = c.get_devices()
d = devices[0]
del devices
assert d.get_driver() == "realtek"
assert d.has_feature(FPrint.DeviceFeature.STORAGE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
d.open_sync()
# Make sure the device holds no templates, so the print below cannot match.
d.clear_storage_sync()
p = FPrint.Print.deserialize(STORED_PRINT)
assert p.get_driver() == "realtek"
assert p.get_device_stored()
assert p.get_finger() == FPrint.Finger.RIGHT_INDEX
print("deleting a print that is not in the device storage")
try:
d.delete_print_sync(p)
except GLib.Error as error:
print("delete reported: {}".format(error.message))
assert error.matches(FPrint.DeviceError.quark(), FPrint.DeviceError.PROTO)
assert error.message
else:
assert False, "deleting a template that is not stored should fail"
del p
print("delete attempt done")
d.close_sync()
del d
del c
File diff suppressed because one or more lines are too long