Commit 89bd5627f490a7bfa5c6bd44a8fca98eb9a9ccb5

Authored by m-holger
1 parent 61b022ec

Add CI test for use of a copy of a destroyed QPDFJob object

Test for #1654
manual/release-notes.rst
... ... @@ -17,8 +17,9 @@ more detail.
17 17 12.3.1: not yet released
18 18 - Bug fixes
19 19  
20   - - Fix a bug causing ``QPDFJob::createQPDF`` to fail if called
21   - from pikepdf.
  20 + - Fix failure of ``QPDFJob::run`` and ``QPDFJob::createQPDF`` when
  21 + called with a copy of a destroyed ``QPDFJob`` object. This affects
  22 + using the job interface from pikepdf.
22 23  
23 24 12.3.0: January 10, 2026
24 25 - Release changes
... ...
qpdf/qtest/qpdf/test102.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +%% Original object ID: 1 0
  6 +1 0 obj
  7 +<<
  8 + /Pages 2 0 R
  9 + /Type /Catalog
  10 +>>
  11 +endobj
  12 +
  13 +%% Original object ID: 2 0
  14 +2 0 obj
  15 +<<
  16 + /Count 1
  17 + /Kids [
  18 + 3 0 R
  19 + ]
  20 + /Type /Pages
  21 +>>
  22 +endobj
  23 +
  24 +%% Page 1
  25 +%% Original object ID: 3 0
  26 +3 0 obj
  27 +<<
  28 + /Contents 4 0 R
  29 + /MediaBox [
  30 + 0
  31 + 0
  32 + 612
  33 + 792
  34 + ]
  35 + /Parent 2 0 R
  36 + /Resources <<
  37 + /Font <<
  38 + /F1 6 0 R
  39 + >>
  40 + /ProcSet 7 0 R
  41 + >>
  42 + /Type /Page
  43 +>>
  44 +endobj
  45 +
  46 +%% Contents for page 1
  47 +%% Original object ID: 4 0
  48 +4 0 obj
  49 +<<
  50 + /Length 5 0 R
  51 +>>
  52 +stream
  53 +BT
  54 + /F1 24 Tf
  55 + 72 720 Td
  56 + (Potato) Tj
  57 +ET
  58 +endstream
  59 +endobj
  60 +
  61 +5 0 obj
  62 +44
  63 +endobj
  64 +
  65 +%% Original object ID: 6 0
  66 +6 0 obj
  67 +<<
  68 + /BaseFont /Helvetica
  69 + /Encoding /WinAnsiEncoding
  70 + /Name /F1
  71 + /Subtype /Type1
  72 + /Type /Font
  73 +>>
  74 +endobj
  75 +
  76 +%% Original object ID: 5 0
  77 +7 0 obj
  78 +[
  79 + /PDF
  80 + /Text
  81 +]
  82 +endobj
  83 +
  84 +xref
  85 +0 8
  86 +0000000000 65535 f
  87 +0000000052 00000 n
  88 +0000000133 00000 n
  89 +0000000242 00000 n
  90 +0000000484 00000 n
  91 +0000000583 00000 n
  92 +0000000629 00000 n
  93 +0000000774 00000 n
  94 +trailer <<
  95 + /Root 1 0 R
  96 + /Size 8
  97 + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
  98 +>>
  99 +startxref
  100 +809
  101 +%%EOF
... ...
qpdf/qtest/qpdfjob.test
... ... @@ -44,7 +44,7 @@ my @good_json = (
44 44 ["underlay-overlay-password", ""],
45 45 ["misc-options", ""],
46 46 );
47   -my $n_tests = 11 + scalar(@bad_json) + (2 * scalar(@good_json));
  47 +my $n_tests = 13 + scalar(@bad_json) + (2 * scalar(@good_json));
48 48  
49 49  
50 50 foreach my $i (@bad_json)
... ... @@ -130,5 +130,13 @@ else
130 130 {$td->FILE => "qpdfjob-ctest-wide.pdf", $td->EXIT_STATUS => 0});
131 131 }
132 132  
  133 +$td->runtest("Copied QPDFJob",
  134 + {$td->COMMAND => "test_driver 102 -"},
  135 + {$td->STRING => "test 102 done\n", $td->EXIT_STATUS => 0},
  136 + $td->NORMALIZE_NEWLINES);
  137 +$td->runtest("check output",
  138 + {$td->FILE => "a.pdf"},
  139 + {$td->FILE => "test102.pdf"});
  140 +
133 141 cleanup();
134 142 $td->report($n_tests);
... ...
qpdf/test_driver.cc
... ... @@ -3584,6 +3584,20 @@ test_101(QPDF&amp; pdf, char const* arg2)
3584 3584 test_helper_throws([](QPDF& q) { (void)QPDFPageLabelDocumentHelper::get(q); });
3585 3585 }
3586 3586  
  3587 +static void
  3588 +test_102(QPDF& pdf, char const* arg2)
  3589 +{
  3590 + // Test using a copy of a QPDFJob object after the original is destroyed
  3591 +
  3592 + auto j = std::make_unique<QPDFJob>();
  3593 + j->initializeFromJson(
  3594 + R"({"inputFile": "minimal.pdf", "outputFile": "a.pdf", "qdf": "", "staticId": ""})");
  3595 + QPDFJob j2 = *j;
  3596 + j = nullptr;
  3597 + auto q = j2.createQPDF();
  3598 + j2.writeQPDF(*q);
  3599 +}
  3600 +
3587 3601 void
3588 3602 runtest(int n, char const* filename1, char const* arg2)
3589 3603 {
... ... @@ -3591,7 +3605,7 @@ runtest(int n, char const* filename1, char const* arg2)
3591 3605 // the test suite to see how the test is invoked to find the file
3592 3606 // that the test is supposed to operate on.
3593 3607  
3594   - std::set<int> ignore_filename = {61, 62, 81, 83, 84, 85, 86, 87, 92, 95, 96, 101};
  3608 + std::set<int> ignore_filename = {61, 62, 81, 83, 84, 85, 86, 87, 92, 95, 96, 101, 102};
3595 3609  
3596 3610 if (n == 0) {
3597 3611 // Throw in some random test cases that don't fit anywhere
... ... @@ -3665,27 +3679,27 @@ runtest(int n, char const* filename1, char const* arg2)
3665 3679 }
3666 3680  
3667 3681 std::map<int, void (*)(QPDF&, char const*)> test_functions = {
3668   - {0, test_0_1}, {1, test_0_1}, {2, test_2}, {3, test_3}, {4, test_4},
3669   - {5, test_5}, {6, test_6}, {7, test_7}, {8, test_8}, {9, test_9},
3670   - {10, test_10}, {11, test_11}, {12, test_12}, {13, test_13}, {14, test_14},
3671   - {15, test_15}, {16, test_16}, {17, test_17}, {18, test_18}, {19, test_19},
3672   - {20, test_20}, {21, test_21}, {22, test_22}, {23, test_23}, {24, test_24},
3673   - {25, test_25}, {26, test_26}, {27, test_27}, {28, test_28}, {29, test_29},
3674   - {30, test_30}, {31, test_31}, {32, test_32}, {33, test_33}, {34, test_34},
3675   - {35, test_35}, {36, test_36}, {37, test_37}, {38, test_38}, {39, test_39},
3676   - {40, test_40}, {41, test_41}, {42, test_42}, {43, test_43}, {44, test_44},
3677   - {45, test_45}, {46, test_46}, {47, test_47}, {48, test_48}, {49, test_49},
3678   - {50, test_50}, {51, test_51}, {52, test_52}, {53, test_53}, {54, test_54},
3679   - {55, test_55}, {56, test_56}, {57, test_57}, {58, test_58}, {59, test_59},
3680   - {60, test_60}, {61, test_61}, {62, test_62}, {63, test_63}, {64, test_64},
3681   - {65, test_65}, {66, test_66}, {67, test_67}, {68, test_68}, {69, test_69},
3682   - {70, test_70}, {71, test_71}, {72, test_72}, {73, test_73}, {74, test_74},
3683   - {75, test_75}, {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79},
3684   - {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83}, {84, test_84},
3685   - {85, test_85}, {86, test_86}, {87, test_87}, {88, test_88}, {89, test_89},
3686   - {90, test_90}, {91, test_91}, {92, test_92}, {93, test_93}, {94, test_94},
3687   - {95, test_95}, {96, test_96}, {97, test_97}, {98, test_98}, {99, test_99},
3688   - {100, test_100}, {101, test_101}};
  3682 + {0, test_0_1}, {1, test_0_1}, {2, test_2}, {3, test_3}, {4, test_4},
  3683 + {5, test_5}, {6, test_6}, {7, test_7}, {8, test_8}, {9, test_9},
  3684 + {10, test_10}, {11, test_11}, {12, test_12}, {13, test_13}, {14, test_14},
  3685 + {15, test_15}, {16, test_16}, {17, test_17}, {18, test_18}, {19, test_19},
  3686 + {20, test_20}, {21, test_21}, {22, test_22}, {23, test_23}, {24, test_24},
  3687 + {25, test_25}, {26, test_26}, {27, test_27}, {28, test_28}, {29, test_29},
  3688 + {30, test_30}, {31, test_31}, {32, test_32}, {33, test_33}, {34, test_34},
  3689 + {35, test_35}, {36, test_36}, {37, test_37}, {38, test_38}, {39, test_39},
  3690 + {40, test_40}, {41, test_41}, {42, test_42}, {43, test_43}, {44, test_44},
  3691 + {45, test_45}, {46, test_46}, {47, test_47}, {48, test_48}, {49, test_49},
  3692 + {50, test_50}, {51, test_51}, {52, test_52}, {53, test_53}, {54, test_54},
  3693 + {55, test_55}, {56, test_56}, {57, test_57}, {58, test_58}, {59, test_59},
  3694 + {60, test_60}, {61, test_61}, {62, test_62}, {63, test_63}, {64, test_64},
  3695 + {65, test_65}, {66, test_66}, {67, test_67}, {68, test_68}, {69, test_69},
  3696 + {70, test_70}, {71, test_71}, {72, test_72}, {73, test_73}, {74, test_74},
  3697 + {75, test_75}, {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79},
  3698 + {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83}, {84, test_84},
  3699 + {85, test_85}, {86, test_86}, {87, test_87}, {88, test_88}, {89, test_89},
  3700 + {90, test_90}, {91, test_91}, {92, test_92}, {93, test_93}, {94, test_94},
  3701 + {95, test_95}, {96, test_96}, {97, test_97}, {98, test_98}, {99, test_99},
  3702 + {100, test_100}, {101, test_101}, {102, test_102}};
3689 3703  
3690 3704 auto fn = test_functions.find(n);
3691 3705 if (fn == test_functions.end()) {
... ...