xref: /aosp_15_r20/external/libgav1/tests/fuzzer/fuzzer_temp_file.h (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1 /*
2  * Copyright 2020 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
18 #define LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
19 
20 // Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
21 // require a file instead of an input buffer.
22 
23 #include <limits.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef _WIN32
29 #include <io.h>
30 #include <windows.h>
31 
32 #define strdup _strdup
33 #define unlink _unlink
34 #else
35 #include <unistd.h>
36 #endif  // _WIN32
37 
38 // Pure-C interface for creating and cleaning up temporary files.
39 
fuzzer_get_tmpfile_with_suffix(const uint8_t * data,size_t size,const char * suffix)40 static char* fuzzer_get_tmpfile_with_suffix(const uint8_t* data, size_t size,
41                                             const char* suffix) {
42 #ifdef _WIN32
43   // GetTempPathA generates '<path>\<pre><uuuu>.TMP'.
44   (void)suffix;  // NOLINT (this could be a C compilation unit)
45   char temp_path[MAX_PATH];
46   const DWORD ret = GetTempPathA(MAX_PATH, temp_path);
47   if (ret == 0 || ret > MAX_PATH) {
48     fprintf(stderr, "Error getting temporary directory name: %lu\n",
49             GetLastError());
50     abort();
51   }
52   char* filename_buffer =
53       (char*)malloc(MAX_PATH);  // NOLINT (this could be a C compilation unit)
54   if (!filename_buffer) {
55     perror("Failed to allocate file name buffer.");
56     abort();
57   }
58   if (GetTempFileNameA(temp_path, "ftf", /*uUnique=*/0, filename_buffer) == 0) {
59     fprintf(stderr, "Error getting temporary file name: %lu\n", GetLastError());
60     abort();
61   }
62 #if defined(_MSC_VER) || defined(MINGW_HAS_SECURE_API)
63   FILE* file;
64   const errno_t err = fopen_s(&file, filename_buffer, "wb");
65   if (err != 0) file = NULL;  // NOLINT (this could be a C compilation unit)
66 #else
67   FILE* file = fopen(filename_buffer, "wb");
68 #endif
69   if (!file) {
70     perror("Failed to open file.");
71     abort();
72   }
73 #else  // !_WIN32
74   if (suffix == NULL) {  // NOLINT (this could be a C compilation unit)
75     suffix = "";
76   }
77   const size_t suffix_len = strlen(suffix);
78   if (suffix_len > INT_MAX) {  // mkstemps takes int for suffixlen param
79     perror("Suffix too long");
80     abort();
81   }
82 
83 #ifdef __ANDROID__
84   const char* leading_temp_path =
85       "/data/local/tmp/generate_temporary_file.XXXXXX";
86 #else
87   const char* leading_temp_path = "/tmp/generate_temporary_file.XXXXXX";
88 #endif
89   const size_t buffer_sz = strlen(leading_temp_path) + suffix_len + 1;
90   char* filename_buffer =
91       (char*)malloc(buffer_sz);  // NOLINT (this could be a C compilation unit)
92   if (!filename_buffer) {
93     perror("Failed to allocate file name buffer.");
94     abort();
95   }
96 
97   if (snprintf(filename_buffer, buffer_sz, "%s%s", leading_temp_path, suffix) >=
98       (int)buffer_sz) {  // NOLINT (this could be a C compilation unit)
99     perror("File name buffer too short.");
100     abort();
101   }
102 
103   const int file_descriptor = mkstemps(filename_buffer, suffix_len);
104   if (file_descriptor < 0) {
105     perror("Failed to make temporary file.");
106     abort();
107   }
108   FILE* file = fdopen(file_descriptor, "wb");
109   if (!file) {
110     perror("Failed to open file descriptor.");
111     close(file_descriptor);
112     abort();
113   }
114 #endif  // _WIN32
115   const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
116   if (bytes_written < size) {
117     fclose(file);
118     fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
119             bytes_written, size);
120     abort();
121   }
122   fclose(file);
123   return filename_buffer;
124 }
125 
fuzzer_get_tmpfile(const uint8_t * data,size_t size)126 static char* fuzzer_get_tmpfile(
127     const uint8_t* data,
128     size_t size) {  // NOLINT (people include this .inc file directly)
129   return fuzzer_get_tmpfile_with_suffix(data, size, NULL);  // NOLINT
130 }
131 
fuzzer_release_tmpfile(char * filename)132 static void fuzzer_release_tmpfile(char* filename) {
133   if (unlink(filename) != 0) {
134     perror("WARNING: Failed to delete temporary file.");
135   }
136   free(filename);
137 }
138 
139 // C++ RAII object for creating temporary files.
140 
141 #ifdef __cplusplus
142 class FuzzerTemporaryFile {
143  public:
FuzzerTemporaryFile(const uint8_t * data,size_t size)144   FuzzerTemporaryFile(const uint8_t* data, size_t size)
145       : original_filename_(fuzzer_get_tmpfile(data, size)) {
146     filename_ = strdup(original_filename_);
147     if (!filename_) {
148       perror("Failed to allocate file name copy.");
149       abort();
150     }
151   }
152 
FuzzerTemporaryFile(const uint8_t * data,size_t size,const char * suffix)153   FuzzerTemporaryFile(const uint8_t* data, size_t size, const char* suffix)
154       : original_filename_(fuzzer_get_tmpfile_with_suffix(data, size, suffix)) {
155     filename_ = strdup(original_filename_);
156     if (!filename_) {
157       perror("Failed to allocate file name copy.");
158       abort();
159     }
160   }
161 
~FuzzerTemporaryFile()162   ~FuzzerTemporaryFile() {
163     free(filename_);
164     fuzzer_release_tmpfile(original_filename_);
165   }
166 
167   FuzzerTemporaryFile(const FuzzerTemporaryFile& other) = delete;
168   FuzzerTemporaryFile operator=(const FuzzerTemporaryFile& other) = delete;
169 
170   FuzzerTemporaryFile(const FuzzerTemporaryFile&& other) = delete;
171   FuzzerTemporaryFile operator=(const FuzzerTemporaryFile&& other) = delete;
172 
filename()173   const char* filename() const { return filename_; }
174 
175   // Returns a mutable pointer to the file name. Should be used sparingly, only
176   // in case the fuzzed API demands it or when making a mutable copy is
177   // inconvenient (e.g., in auto-generated code).
mutable_filename()178   char* mutable_filename() const { return filename_; }
179 
180  private:
181   char* original_filename_;
182 
183   // A mutable copy of the original filename, returned by the accessor. This
184   // guarantees that the original filename can always be used to release the
185   // temporary path.
186   char* filename_;
187 };
188 #endif  // __cplusplus
189 #endif  // LIBGAV1_TESTS_FUZZER_FUZZER_TEMP_FILE_H_
190