Use of Glib::thread_init() was deprecated in glibmm 2.32 [1]. The
oldest supported distributions have these versions:
Debian 8 glibmm 2.42.0
RHEL / CentOS 7 glibmm 2.56.0
SLES 12 glibmm 2.38.1
Ubuntu 14.04 LTS glibmm 2.39.93
Checking further the glibmm 2.32 reference manual says this about
Glib::thread_init() [2]:
Initializes the GLib thread system.
Deprecated:
Calling thread_init() is no longer necessary and no longer has any
effect.
However only some of the glibmm example programs had Glib::thread_init()
removed, others had it replaced by Glib::init() [3]. Again the glibmm
2.32 reference manual says this about Glib::init() [4]:
Initialize glibmm.
You may call this more than once. You do not need to call this if
you are using Glib::MainLoop or Gtk::Main, because they call it for
you.
GParted does call Gtk::Main and test_PipeCapture does call
Glib::MainLoop. Therefore just raise the minimum version to glibmm 2.32
and remove both calls to Glib::thread_init().
[1] Glibmm 2.32 NEWS file
https://gitlab.gnome.org/GNOME/glibmm/blob/2.32.0/NEWS#L207
[2] glibmm 2.32, glibmm: Glib Namespace Reference, Glib::thread_init()
https://developer.gnome.org/glibmm/2.32/namespaceGlib.html#ab26d01c776801f1fff00753e97af4fc7
[3] glibmm commit "Avoid use of deprecates API in tests and examples."
3e0fbb22c0
[4] glibmm 2.32, glibmm: Glib Namespace Reference, Glib::init()
https://developer.gnome.org/glibmm/2.32/namespaceGlib.html#ac90aee10d0b90e3d8a96a86b5394f87bCloses!22 - Increase minimums to libparted 2.2 and glibmm 2.32
Test that binary data that happens to be the start of a multi-byte UTF-8
character but then contains a NUL byte is successfully read. The test
currently detects failure thus:
$ ./test_PipeCapture
...
[ RUN ] PipeCaptureTest.ReadNULByteInMiddleOfMultiByteUTF8Character
test_PipeCapture.cc:346: Failure
Expected: expectedstr
Of length: 7
To be equal to: capturedstr.raw()
Of length: 0
With first binary difference:
< 0x00000000 "._45678" 00 5F 34 35 36 37 38
--
> 0x00000000 ""
[ FAILED ] PipeCaptureTest.ReadNULByteInMiddleOfMultiByteUTF8Character (0 ms)
...
Bug 777973 - Segmentation fault on bad disk
Test currently detects failure thus:
$ ./test_PipeCapture
...
[ RUN ] PipeCaptureTest.ReadEmbeddedNULCharacter
unknown file: Failure
C++ exception with description "std::bad_alloc" thrown in the test body.
[ FAILED ] PipeCaptureTest.ReadEmbeddedNULCharacter (31917 ms)
...
Bug 777973 - Segmentation fault on bad disk
PipeCapture::OnReadable() has been almost completely re-written but this
test is still failing thus:
$ ./test_PipeCapture
...
[ RUN ] PipeCaptureTest.MinimalBinaryCrash777973
test_PipeCapture.cc:313: Failure
Expected: inputstr
Of length: 27
To be equal to: capturedstr.raw()
Of length: 26
With first binary difference:
< 0x00000010 "...!......." A9 C2 A0 21 E2 95 9F E2 88 A9 C2
--
> 0x00000010 "...!......" A9 C2 A0 21 E2 95 9F E2 88 A9
[ FAILED ] PipeCaptureTest.MinimalBinaryCrash777973 (0 ms)
...
The OnReadable() code specifically skips invalid bytes which aren't part
of valid UTF-8 characters, because they can't be displayed to the user.
The final C2 byte is the start of a multi-byte UTF-8 character, so on
it's own is invalid. Therefore PipeCapture skips it. Update expected
string accordingly. Now the test passes.
Bug 777973 - Segmentation fault on bad disk
Initialise capture string with sacrificial text before each test.
Existing tests confirm this is cleared first by checking the captured
string matches the input string.
Bug 777973 - Segmentation fault on bad disk
A user had a very corrupt FAT file system and fsck.fat was reporting
binary data in file names with errors. GParted crashed reading this
output. Boiled down the problematic fsck.fat output to a sample 27
bytes which still triggers a crash and created a test for it. The test
crashes test_PipeCapture program too.
$ ./test_PipeCapture
...
[ RUN ] PipeCaptureTest.MinimalBinaryCrash777973
Segmentation fault (core dumped)
$ echo $?
139
However it still produces a non-zero exit status and the autotools test
runner detects this so 'make check' still reports failure.
$ make check
...
make[2]: Entering directory `/home/centos/programming/c/gparted/tests'
PASS: test_dummy
PASS: test_BlockSpecial
../test-driver: line 95: 16152 Segmentation fault "$@" > $log_file 2>&1
FAIL: test_PipeCapture
...
============================================================================
Testsuite summary for gparted 0.28.1-git
============================================================================
# TOTAL: 3
# PASS: 2
# SKIP: 0
# XFAIL: 0
# FAIL: 1
# XPASS: 0
# ERROR: 0
============================================================================
See tests/test-suite.log
Please report to https://bugzilla.gnome.org/enter_bug.cgi?product=gparted
============================================================================
make[2]: *** [test-suite.log] Error 1
make[2]: Leaving directory `/home/centos/programming/c/gparted/tests'
make[1]: *** [check-TESTS] Error 2
make[1]: Leaving directory `/home/centos/programming/c/gparted/tests'
make: *** [check-am] Error 2
$ echo $?
2
Bug 777973 - Segmentation fault on bad disk
Also ensure that the PipeCapture calls registered update callbacks and
that the data so far captured matches the leading portion of the input.
Bug 777973 - Segmentation fault on bad disk
Google Test string comparison asserts are only designed of C style
strings containing printable text of one or more lines with a
terminating NUL character. GParted is crashing when PipeCapture is
reading the binary file names being reported by fsck.fat from a very
corrupted FAT file system. Therefore need to be able to compare and
report differences of binary data stored in C++ std::string and
Glib::ustrings. Write a specific assertion to handle this.
Now these sample tests:
TEST_F( PipeCaptureTest, BinaryStringFailure )
{
inputstr = "AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCC";
capturedstr = "AAAAAAAAAAAAAAAABBBBBBBBBBbbbb";
EXPECT_BINARYSTRINGEQ( inputstr, capturedstr.raw() );
}
TEST_F( PipeCaptureTest, LeadingBinaryStringFailure )
{
inputstr = "The quick brown fox jumps over the lazy dog";
capturedstr = "The quick brown fox\n";
EXPECT_BINARYSTRINGEQ( inputstr.substr( 0, capturedstr.raw().length() ),
capturedstr.raw() );
}
report failure like this:
$ ./test_PipeCapture
...
[ RUN ] PipeCaptureTest.BinaryStringFailure
test_PipeCapture.cc:270: Failure
Expected: inputstr
Of length: 48
To be equal to: capturedstr.raw()
Of length: 30
With first binary difference:
< 0x00000010 "BBBBBBBBBBBBBBBB" 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42
--
> 0x00000010 "BBBBBBBBBBbbbb" 42 42 42 42 42 42 42 42 42 42 62 62 62 62
[ FAILED ] PipeCaptureTest.BinaryStringFailure (1 ms)
[ RUN ] PipeCaptureTest.LeadingBinaryStringFailure
test_PipeCapture.cc:278: Failure
Expected: inputstr.substr( 0, capturedstr.raw().length() )
Of length: 20
To be equal to: capturedstr.raw()
Of length: 20
With first binary difference:
< 0x00000010 "fox " 66 6F 78 20
--
> 0x00000010 "fox." 66 6F 78 0A
[ FAILED ] PipeCaptureTest.LeadingBinaryStringFailure (0 ms)
...
Bug 777973 - Segmentation fault on bad disk
Add test sending 1 MiB of ASCII test into PipeCapture to read. This
requires multiple reads and rewites through the pipe.
This is as much a check of the threading in the PipeCaptureTest class as
it is of PipeCapture itself. This is because a single thread might
block reading from a pipe waiting for itself to write to the pipe.
Deadlock. Hence the requirement to use a separate thread for reading
and writing.
Bug 777973 - Segmentation fault on bad disk
On CentOS 6, with glib/glibmm 2.28, running the tests fails thus:
$ ./test_PipeCapture
Running main() from gtest_main.cc
[==========] Running 4 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from PipeCaptureTest
[ RUN ] PipeCaptureTest.EmptyPipe
GLib-ERROR **: The thread system is not yet initialized.
aborting...
Aborted (core dumped)
For glib before version 2.32, the threading system must be explicitly
initialised with a call to g_thread_init(), or the Glibmm
Glib::thread_init() equivalent to prevent this error.
Deprecated thread API, g_thread_init()
https://developer.gnome.org/glib/stable/glib-Deprecated-Thread-APIs.html#g-thread-init
Do this by providing our own main() which also initialises the Glib
threading system, rather using and linking in the Google Test provided
main().
Bug 777973 - Segmentation fault on bad disk
So far just tests sending 0 bytes and a few ASCII bytes into a pipe and
that they are read correctly by the PipeCapture class.
Bug 777973 - Segmentation fault on bad disk