/src/dcmtk-fuzzers/dcmtk_image_fuzzer.cc
Line | Count | Source |
1 | | // Copyright 2026 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | /////////////////////////////////////////////////////////////////////////// |
16 | | #include <cstdint> |
17 | | #include <cstddef> |
18 | | #include <cstdlib> |
19 | | #include <new> |
20 | | |
21 | | #include "dcmtk/dcmdata/dctk.h" |
22 | | #include "dcmtk/dcmdata/dcistrmb.h" |
23 | | #include "dcmtk/dcmdata/dcxfer.h" |
24 | | #include "dcmtk/dcmdata/dcrledrg.h" |
25 | | #include "dcmtk/dcmimage/diregist.h" |
26 | | #include "dcmtk/dcmimgle/dcmimage.h" |
27 | | #include "dcmtk/dcmimgle/diutils.h" |
28 | | #include "dcmtk/dcmjpeg/djdecode.h" |
29 | | #include "dcmtk/dcmjpls/djdecode.h" |
30 | | |
31 | | static constexpr std::size_t kNewNothrowCap = 8 * 1024 * 1024; |
32 | | |
33 | 403 | void* operator new(std::size_t n, const std::nothrow_t&) noexcept { |
34 | 403 | if (n > kNewNothrowCap) return nullptr; |
35 | 403 | try { return ::operator new(n); } catch (...) { return nullptr; } |
36 | 403 | } |
37 | 16.0k | void* operator new[](std::size_t n, const std::nothrow_t&) noexcept { |
38 | 16.0k | if (n > kNewNothrowCap) return nullptr; |
39 | 15.2k | try { return ::operator new[](n); } catch (...) { return nullptr; } |
40 | 15.2k | } |
41 | | |
42 | 1 | static void cleanupCodecs() { |
43 | 1 | DJDecoderRegistration::cleanup(); |
44 | 1 | DJLSDecoderRegistration::cleanup(); |
45 | 1 | DcmRLEDecoderRegistration::cleanup(); |
46 | 1 | } |
47 | | |
48 | 1 | static bool registerCodecs() { |
49 | 1 | DJDecoderRegistration::registerCodecs(); |
50 | 1 | DJLSDecoderRegistration::registerCodecs(); |
51 | 1 | DcmRLEDecoderRegistration::registerCodecs(); |
52 | 1 | std::atexit(cleanupCodecs); |
53 | 1 | return true; |
54 | 1 | } |
55 | | |
56 | 3.34k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
57 | 3.34k | static bool dict_set = (setenv("DCMDICTPATH", "/out/dicom.dic", 0), true); |
58 | 3.34k | static bool codecs_set = registerCodecs(); |
59 | 3.34k | (void)dict_set; |
60 | 3.34k | (void)codecs_set; |
61 | | |
62 | 3.34k | DcmInputBufferStream in; |
63 | 3.34k | in.setBuffer((void*)data, size); |
64 | 3.34k | in.setEos(); |
65 | | |
66 | 3.34k | DcmFileFormat file; |
67 | 3.34k | const Uint32 kMaxReadLen = 256 * 1024; |
68 | | |
69 | 3.34k | if (file.read(in, EXS_Unknown, EGL_noChange, kMaxReadLen).good()) { |
70 | 403 | if (auto* ds = file.getDataset()) { |
71 | 403 | DicomImage* image = new (std::nothrow) DicomImage(&file, ds->getOriginalXfer()); |
72 | 403 | if (image && image->getStatus() == EIS_Normal) { |
73 | 0 | unsigned long frames = image->getFrameCount(); |
74 | 0 | if (frames > 16) frames = 16; |
75 | 0 | for (unsigned long f = 0; f < frames; ++f) |
76 | 0 | (void)image->getOutputData(8, f); |
77 | 0 | } |
78 | 403 | delete image; |
79 | 403 | } |
80 | 403 | } |
81 | 3.34k | return 0; |
82 | 3.34k | } |