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