Bug Summary

File:usr/include/string.h
Warning:line 281, column 10
Value of 'errno' was not checked and may be overwritten by function '__builtin_strrchr'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name updatecommon.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/mozapps/update/common -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/mozapps/update/common -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D NS_NO_XPCOM -D MOZ_APP_BASENAME="Firefox" -I /root/firefox-clang/toolkit/mozapps/update/common -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/mozapps/update/common -I /root/firefox-clang/other-licenses/nsis/Contrib/CityHash/cityhash -I /root/firefox-clang/toolkit/components/jsoncpp/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/toolkit/mozapps/update/common/updatecommon.cpp

/root/firefox-clang/toolkit/mozapps/update/common/updatecommon.cpp

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "updatedefines.h"
6#if defined(XP_WIN)
7# include <windows.h>
8# include <winioctl.h> // for FSCTL_GET_REPARSE_POINT
9# include <shlobj.h>
10# ifndef RRF_SUBKEY_WOW6464KEY
11# define RRF_SUBKEY_WOW6464KEY 0x00010000
12# endif
13#endif
14
15#if defined(XP_MACOSX)
16# include <os/log.h>
17#endif
18
19#include <stdio.h>
20#include <stdarg.h>
21
22#include "updatecommon.h"
23#ifdef XP_WIN
24# include "updatehelper.h"
25# include "nsWindowsHelpers.h"
26# include "mozilla/UniquePtr.h"
27# include "mozilla/WinHeaderOnlyUtils.h"
28
29// This struct isn't in any SDK header, so this definition was copied from:
30// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_reparse_data_buffer
31typedef struct _REPARSE_DATA_BUFFER {
32 ULONG ReparseTag;
33 USHORT ReparseDataLength;
34 USHORT Reserved;
35 union {
36 struct {
37 USHORT SubstituteNameOffset;
38 USHORT SubstituteNameLength;
39 USHORT PrintNameOffset;
40 USHORT PrintNameLength;
41 ULONG Flags;
42 WCHAR PathBuffer[1];
43 } SymbolicLinkReparseBuffer;
44 struct {
45 USHORT SubstituteNameOffset;
46 USHORT SubstituteNameLength;
47 USHORT PrintNameOffset;
48 USHORT PrintNameLength;
49 WCHAR PathBuffer[1];
50 } MountPointReparseBuffer;
51 struct {
52 UCHAR DataBuffer[1];
53 } GenericReparseBuffer;
54 } DUMMYUNIONNAME;
55} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
56#endif
57
58void UpdateLog::Init(NS_tchar* logFilePath) {
59 if (logFP) {
60 return;
61 }
62
63 // When the path is over the length limit disable logging by not opening the
64 // file and not setting logFP.
65 int dstFilePathLen = NS_tstrlenstrlen(logFilePath);
66 if (dstFilePathLen > 0 && dstFilePathLen < MAXPATHLEN4096 - 1) {
67 NS_tstrncpystrncpy(mDstFilePath, logFilePath, MAXPATHLEN4096);
68#if defined(XP_WIN) || defined(XP_MACOSX)
69 logFP = CreateAndOpenFile(mDstFilePath, false);
70 if (logFP == nullptr) {
71 LogToOS(NS_T("Failed to create FILE*")"Failed to create FILE*");
72 }
73#else
74 // On platforms that have an updates directory in the installation directory
75 // (e.g. platforms other than Windows and Mac) the update log is written to
76 // a temporary file and then to the update log file. This is needed since
77 // the installation directory is moved during a replace request. This can be
78 // removed when the platform's updates directory is located outside of the
79 // installation directory.
80 logFP = tmpfile();
81#endif
82 }
83}
84
85void UpdateLog::Finish() {
86 if (!logFP) {
1
Assuming field 'logFP' is non-null
2
Taking false branch
87 return;
88 }
89
90#if !defined(XP_WIN) && !defined(XP_MACOSX)
91 const int blockSize = 1024;
92 char buffer[blockSize];
93 fflush(logFP);
94 rewind(logFP);
3
After calling 'rewind' reading 'errno' is required to find out if the call has failed
95
96 FILE* updateLogFP = CreateAndOpenFile(mDstFilePath, true);
4
Calling 'CreateAndOpenFile'
97 if (updateLogFP == nullptr) {
98 return;
99 }
100
101 while (!feof(logFP)) {
102 size_t read = fread(buffer, 1, blockSize, logFP);
103 if (ferror(logFP)) {
104 fclose(logFP);
105 logFP = nullptr;
106 fclose(updateLogFP);
107 updateLogFP = nullptr;
108 return;
109 }
110
111 size_t written = 0;
112
113 while (written < read) {
114 size_t chunkWritten = fwrite(buffer, 1, read - written, updateLogFP);
115 if (chunkWritten <= 0) {
116 fclose(logFP);
117 logFP = nullptr;
118 fclose(updateLogFP);
119 updateLogFP = nullptr;
120 return;
121 }
122
123 written += chunkWritten;
124 }
125 }
126 fclose(updateLogFP);
127 updateLogFP = nullptr;
128#endif
129
130 fclose(logFP);
131 logFP = nullptr;
132}
133
134void UpdateLog::Flush() {
135 if (!logFP) {
136 return;
137 }
138
139 fflush(logFP);
140}
141
142void UpdateLog::PrintTimestampPrefix() {
143 if (!logFP) {
144 return;
145 }
146
147 time_t rawtime = time(nullptr);
148 struct tm* timeinfo = localtime(&rawtime);
149
150 if (nullptr != timeinfo) {
151 // attempt to format the time similar to rfc-3339 so that it works with
152 // sort(1). xxxx-xx-xx xx:xx:xx+xxxx -> 24 chars + 1 NUL
153 const size_t buffer_size = 25;
154 char buffer[buffer_size] = {0};
155
156 if (0 == strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S%z", timeinfo)) {
157 buffer[0] = '\0'; // reset buffer into a defined state and try posix ts
158 if (0 > snprintf(buffer, buffer_size, "%d", (int)mktime(timeinfo))) {
159 buffer[0] = '\0'; // reset and give up
160 }
161 }
162
163 fprintf(logFP, "%s: ", buffer);
164 }
165}
166
167void UpdateLog::Printf(const char* fmt, ...) {
168 if (!logFP) {
169 return;
170 }
171
172 PrintTimestampPrefix();
173
174 va_list ap;
175 va_start(ap, fmt)__builtin_va_start(ap, fmt);
176 vfprintf(logFP, fmt, ap);
177 va_end(ap)__builtin_va_end(ap);
178
179 fprintf(logFP, "\n");
180 // When the updater crashes on Windows the log file won't be flushed and this
181 // can make it easier to debug what is going on.
182 fflush(logFP);
183}
184
185void UpdateLog::WarnPrintf(const char* fmt, ...) {
186 if (!logFP) {
187 return;
188 }
189
190 PrintTimestampPrefix();
191
192 va_list ap;
193 va_start(ap, fmt)__builtin_va_start(ap, fmt);
194 fprintf(logFP, "*** Warning: ");
195 vfprintf(logFP, fmt, ap);
196 fprintf(logFP, "***\n");
197 va_end(ap)__builtin_va_end(ap);
198 // When the updater crashes on Windows the log file won't be flushed and this
199 // can make it easier to debug what is going on.
200 fflush(logFP);
201}
202
203/**
204 * Creates and opens a file for logging in read/write mode.
205 *
206 * @param filePath The path of the log file.
207 * @param binary If the file should be opened as binary (ignored on
208 * macOS/Linux).
209 * @return a pointer to the FILE struct or nullptr on error.
210 */
211FILE* CreateAndOpenFile(NS_tchar* filePath, bool binary) {
212#ifdef XP_WIN
213 return NS_tfopenfopen(filePath, binary ? NS_T("wb+")"wb+" : NS_T("w+")"w+");
214#else
215 LogToOS(NS_T("Opening logfile")"Opening logfile");
216 NS_tchar* lastSeperator = NS_tstrrchrstrrchr(filePath, '/');
5
Calling 'strrchr'
217 if (lastSeperator == nullptr) {
218 // No separator, disable logging.
219 return nullptr;
220 }
221
222 const NS_tchar templateSuffix[] = NS_T("/temp.XXXXXX")"/temp.XXXXXX";
223 size_t templateLen = NS_tstrlenstrlen(templateSuffix);
224
225 long dirLength = lastSeperator - filePath;
226 // +1 to account for the \0 terminator
227 if (dirLength < 0 ||
228 (unsigned long)dirLength >= MAXPATHLEN4096 - (templateLen + 1)) {
229 // Too short, or too long. Disable logging.
230 return nullptr;
231 }
232
233 NS_tchar tmpFilePath[MAXPATHLEN4096] = {L'\0'};
234 // Use memcpy here to only copy the directory portion of filePath
235 // and using strncpy triggered GCC's stringop-truncation error because
236 // filePath's \0 terminator wasn't being carried over. This isn't a problem
237 // here because the next strncpy adds it.
238 memcpy(tmpFilePath, filePath, dirLength);
239 NS_tstrncpystrncpy(tmpFilePath + dirLength, templateSuffix, MAXPATHLEN4096 - dirLength);
240
241 int fd = mkstemp(tmpFilePath);
242 if (fd == -1) {
243 LogToOS(NS_T("Failed to open tmp")"Failed to open tmp");
244 return nullptr;
245 }
246
247 if (rename(tmpFilePath, filePath) == -1) {
248 LogToOS(NS_T("Failed to rename")"Failed to rename");
249 close(fd);
250 return nullptr;
251 }
252
253 LogToOS(NS_T("Opening file*")"Opening file*");
254 return fdopen(fd, "w+");
255#endif
256}
257
258#ifdef XP_WIN
259/**
260 * Determine if a path contains symlinks or junctions to disallowed locations
261 *
262 * @param fullPath The full path to check.
263 * @return true if the path contains invalid links or on errors,
264 * false if the check passes and the path can be used
265 */
266bool PathContainsInvalidLinks(wchar_t* const fullPath) {
267 wchar_t pathCopy[MAXPATHLEN4096 + 1] = L"";
268 wcsncpy(pathCopy, fullPath, MAXPATHLEN4096);
269 wchar_t* remainingPath = nullptr;
270 wchar_t* nextToken = wcstok_s(pathCopy, L"\\", &remainingPath);
271 wchar_t* partialPath = nextToken;
272
273 while (nextToken) {
274 if ((GetFileAttributesW(partialPath) & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
275 nsAutoHandle h(CreateFileW(
276 partialPath, 0,
277 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
278 OPEN_EXISTING,
279 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr));
280 if (h == INVALID_HANDLE_VALUE) {
281 if (GetLastError() == ERROR_FILE_NOT_FOUND) {
282 // The path can't be an invalid link if it doesn't exist.
283 return false;
284 } else {
285 return true;
286 }
287 }
288
289 mozilla::UniquePtr<UINT8[]> byteBuffer =
290 mozilla::MakeUnique<UINT8[]>(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
291 ZeroMemory(byteBuffer.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
292 REPARSE_DATA_BUFFER* buffer = (REPARSE_DATA_BUFFER*)byteBuffer.get();
293 DWORD bytes = 0;
294 if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
295 MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, nullptr)) {
296 return true;
297 }
298
299 wchar_t* reparseTarget = nullptr;
300 switch (buffer->ReparseTag) {
301 case IO_REPARSE_TAG_MOUNT_POINT:
302 reparseTarget =
303 buffer->MountPointReparseBuffer.PathBuffer +
304 (buffer->MountPointReparseBuffer.SubstituteNameOffset /
305 sizeof(wchar_t));
306 if (buffer->MountPointReparseBuffer.SubstituteNameLength <
307 ARRAYSIZE(L"\\??\\")) {
308 return false;
309 }
310 break;
311 case IO_REPARSE_TAG_SYMLINK:
312 reparseTarget =
313 buffer->SymbolicLinkReparseBuffer.PathBuffer +
314 (buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset /
315 sizeof(wchar_t));
316 if (buffer->SymbolicLinkReparseBuffer.SubstituteNameLength <
317 ARRAYSIZE(L"\\??\\")) {
318 return false;
319 }
320 break;
321 default:
322 return true;
323 break;
324 }
325
326 if (!reparseTarget) {
327 return false;
328 }
329 if (wcsncmp(reparseTarget, L"\\??\\", ARRAYSIZE(L"\\??\\") - 1) != 0) {
330 return true;
331 }
332 }
333
334 nextToken = wcstok_s(nullptr, L"\\", &remainingPath);
335 PathAppendW(partialPath, nextToken);
336 }
337
338 return false;
339}
340
341/**
342 * Determine if a path is located within Program Files, either native or x86
343 *
344 * @param fullPath The full path to check.
345 * @return true if fullPath begins with either Program Files directory,
346 * false if it does not or if an error is encountered
347 */
348bool IsProgramFilesPath(NS_tchar* fullPath) {
349 // Make sure we don't try to compare against a short path.
350 DWORD longInstallPathChars = GetLongPathNameW(fullPath, nullptr, 0);
351 if (longInstallPathChars == 0) {
352 return false;
353 }
354 mozilla::UniquePtr<wchar_t[]> longInstallPath =
355 mozilla::MakeUnique<wchar_t[]>(longInstallPathChars);
356 if (!GetLongPathNameW(fullPath, longInstallPath.get(),
357 longInstallPathChars)) {
358 return false;
359 }
360
361 // First check for Program Files (x86).
362 {
363 PWSTR programFiles32PathRaw = nullptr;
364 // FOLDERID_ProgramFilesX86 gets native Program Files directory on a 32-bit
365 // OS or the (x86) directory on a 64-bit OS regardless of this binary's
366 // bitness.
367 if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, nullptr,
368 &programFiles32PathRaw))) {
369 // That call should never fail on any supported OS version.
370 return false;
371 }
372 mozilla::UniquePtr<wchar_t, mozilla::CoTaskMemFreeDeleter>
373 programFiles32Path(programFiles32PathRaw);
374 // We need this path to have a trailing slash so our prefix test doesn't
375 // match on a different folder which happens to have a name beginning with
376 // the prefix we're looking for but then also more characters after that.
377 size_t length = wcslen(programFiles32Path.get());
378 if (length == 0) {
379 return false;
380 }
381 if (programFiles32Path.get()[length - 1] == L'\\') {
382 if (wcsnicmp(longInstallPath.get(), programFiles32Path.get(), length) ==
383 0) {
384 return true;
385 }
386 } else {
387 // Allocate space for a copy of the string along with a terminator and one
388 // extra character for the trailing backslash.
389 length += 1;
390 mozilla::UniquePtr<wchar_t[]> programFiles32PathWithSlash =
391 mozilla::MakeUnique<wchar_t[]>(length + 1);
392
393 NS_tsnprintfsnprintf(programFiles32PathWithSlash.get(), length + 1, NS_T("%s\\")"%s\\",
394 programFiles32Path.get());
395
396 if (wcsnicmp(longInstallPath.get(), programFiles32PathWithSlash.get(),
397 length) == 0) {
398 return true;
399 }
400 }
401 }
402
403 // If we didn't find (x86), check for the native Program Files.
404 {
405 // In case we're a 32-bit binary on 64-bit Windows, we now have a problem
406 // getting the right "native" Program Files path, which is that there is no
407 // FOLDERID_* value that returns that path. So we always read that one out
408 // of its canonical registry location instead. If we're on a 32-bit OS, this
409 // will be the same path that we just checked. First get the buffer size to
410 // allocate for the path.
411 DWORD length = 0;
412 if (RegGetValueW(HKEY_LOCAL_MACHINE,
413 L"Software\\Microsoft\\Windows\\CurrentVersion",
414 L"ProgramFilesDir", RRF_RT_REG_SZ | RRF_SUBKEY_WOW6464KEY,
415 nullptr, nullptr, &length) != ERROR_SUCCESS) {
416 return false;
417 }
418 // RegGetValue returns the length including the terminator, but it's in
419 // bytes, so convert that to characters.
420 DWORD lengthChars = (length / sizeof(wchar_t));
421 if (lengthChars <= 1) {
422 return false;
423 }
424 mozilla::UniquePtr<wchar_t[]> programFilesNativePath =
425 mozilla::MakeUnique<wchar_t[]>(lengthChars);
426
427 // Now actually read the value.
428 if (RegGetValueW(
429 HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion",
430 L"ProgramFilesDir", RRF_RT_REG_SZ | RRF_SUBKEY_WOW6464KEY, nullptr,
431 programFilesNativePath.get(), &length) != ERROR_SUCCESS) {
432 return false;
433 }
434 size_t nativePathStrLen =
435 wcsnlen_s(programFilesNativePath.get(), lengthChars);
436 if (nativePathStrLen == 0) {
437 return false;
438 }
439
440 // As before, append a backslash if there isn't one already.
441 if (programFilesNativePath.get()[nativePathStrLen - 1] == L'\\') {
442 if (wcsnicmp(longInstallPath.get(), programFilesNativePath.get(),
443 nativePathStrLen) == 0) {
444 return true;
445 }
446 } else {
447 // Allocate space for a copy of the string along with a terminator and one
448 // extra character for the trailing backslash.
449 nativePathStrLen += 1;
450 mozilla::UniquePtr<wchar_t[]> programFilesNativePathWithSlash =
451 mozilla::MakeUnique<wchar_t[]>(nativePathStrLen + 1);
452
453 NS_tsnprintfsnprintf(programFilesNativePathWithSlash.get(), nativePathStrLen + 1,
454 NS_T("%s\\")"%s\\", programFilesNativePath.get());
455
456 if (wcsnicmp(longInstallPath.get(), programFilesNativePathWithSlash.get(),
457 nativePathStrLen) == 0) {
458 return true;
459 }
460 }
461 }
462
463 return false;
464}
465#endif
466
467/**
468 * Performs checks of a full path for validity for this application.
469 *
470 * @param origFullPath
471 * The full path to check.
472 * @return true if the path is valid for this application and false otherwise.
473 */
474bool IsValidFullPath(NS_tchar* origFullPath) {
475 // Subtract 1 from MAXPATHLEN for null termination.
476 if (NS_tstrlenstrlen(origFullPath) > MAXPATHLEN4096 - 1) {
477 // The path is longer than acceptable for this application.
478 return false;
479 }
480
481#ifdef XP_WIN
482 NS_tchar testPath[MAXPATHLEN4096] = {NS_T('\0')'\0'};
483 // GetFullPathNameW will replace / with \ which PathCanonicalizeW requires.
484 if (GetFullPathNameW(origFullPath, MAXPATHLEN4096, testPath, nullptr) == 0) {
485 // Unable to get the full name for the path (e.g. invalid path).
486 return false;
487 }
488
489 NS_tchar canonicalPath[MAXPATHLEN4096] = {NS_T('\0')'\0'};
490 if (!PathCanonicalizeW(canonicalPath, testPath)) {
491 // Path could not be canonicalized (e.g. invalid path).
492 return false;
493 }
494
495 // Check if the path passed in resolves to a differerent path.
496 if (NS_tstricmpstrcasecmp(origFullPath, canonicalPath) != 0) {
497 // Case insensitive string comparison between the supplied path and the
498 // canonical path are not equal. This will prevent directory traversal and
499 // the use of / in paths since they are converted to \.
500 return false;
501 }
502
503 NS_tstrncpystrncpy(testPath, origFullPath, MAXPATHLEN4096);
504 if (!PathStripToRootW(testPath)) {
505 // It should always be possible to strip a valid path to its root.
506 return false;
507 }
508
509 if (origFullPath[0] == NS_T('\\')'\\') {
510 // Only allow UNC server share paths.
511 if (!PathIsUNCServerShareW(testPath)) {
512 return false;
513 }
514 }
515
516 if (PathContainsInvalidLinks(canonicalPath)) {
517 return false;
518 }
519#else
520 // Only allow full paths.
521 if (origFullPath[0] != NS_T('/')'/') {
522 return false;
523 }
524
525 // The path must not traverse directories
526 if (NS_tstrstrstrstr(origFullPath, NS_T("/../")"/../") != nullptr) {
527 return false;
528 }
529
530 // The path shall not have a path traversal suffix
531 const NS_tchar invalidSuffix[] = NS_T("/..")"/..";
532 size_t pathLen = NS_tstrlenstrlen(origFullPath);
533 size_t invalidSuffixLen = NS_tstrlenstrlen(invalidSuffix);
534 if (invalidSuffixLen <= pathLen &&
535 NS_tstrncmpstrncmp(origFullPath + pathLen - invalidSuffixLen, invalidSuffix,
536 invalidSuffixLen) == 0) {
537 return false;
538 }
539#endif
540 return true;
541}
542
543#if defined(XP_MACOSX)
544// This is never deallocated by the system
545MOZ_RUNINIT static os_log_t updaterLogger =
546 os_log_create("org.mozilla.updater", "Updater");
547#endif
548
549/**
550 * Logs a message to the system log for debugging purposes before our log
551 * file has been set up.
552 *
553 * @param message
554 * The message to log.
555 */
556void LogToOS(const NS_tchar* message) {
557#if defined(XP_MACOSX)
558 os_log(updaterLogger, "%{public}s", message);
559#endif
560}

/usr/include/string.h

1/* Copyright (C) 1991-2026 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18/*
19 * ISO C99 Standard: 7.21 String handling <string.h>
20 */
21
22#ifndef _STRING_H1
23#define _STRING_H1 1
24
25#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION
26#include <bits/libc-header-start.h>
27
28__BEGIN_DECLSextern "C" {
29
30#if __GLIBC_USE (ISOC23)1
31# define __STDC_VERSION_STRING_H__202311L 202311L
32#endif
33
34/* Get size_t and NULL from <stddef.h>. */
35#define __need_size_t
36#define __need_NULL
37#include <stddef.h>
38
39/* Tell the caller that we provide correct C++ prototypes. */
40#if defined __cplusplus202002L && (__GNUC_PREREQ (4, 4)((4 << 16) + 2 >= ((4) << 16) + (4)) \
41 || __glibc_clang_prereq (3, 5)((23 << 16) + 1 >= ((3) << 16) + (5)))
42# define __CORRECT_ISO_CPP_STRING_H_PROTO
43#endif
44
45
46/* Copy N bytes of SRC to DEST. */
47extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
48 size_t __n) __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
49/* Copy N bytes of SRC to DEST, guaranteeing
50 correct behavior for overlapping strings. */
51extern void *memmove (void *__dest, const void *__src, size_t __n)
52 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
53
54/* Copy no more than N bytes of SRC to DEST, stopping when C is found.
55 Return the position in DEST one byte past where C was copied,
56 or NULL if C was not found in the first N bytes of SRC. */
57#if defined __USE_MISC1 || defined __USE_XOPEN1 || __GLIBC_USE (ISOC23)1
58extern void *memccpy (void *__restrict __dest, const void *__restrict __src,
59 int __c, size_t __n)
60 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))) __attr_access ((__write_only__, 1, 4));
61#endif /* Misc || X/Open. */
62
63
64/* Set N bytes of S to C. */
65extern void *memset (void *__s, int __c, size_t __n) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
66
67#if defined __USE_MISC1 || __GLIBC_USE (ISOC23)1
68/* Like memset, but the compiler will not delete a call to this
69 function, even if S is dead after the call. */
70extern void *memset_explicit (void *__s, int __c, size_t __n)
71 __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))) __fortified_attr_access (__write_only__, 1, 3);
72#endif
73
74/* Compare N bytes of S1 and S2. */
75extern int memcmp (const void *__s1, const void *__s2, size_t __n)
76 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
77
78/* Compare N bytes of S1 and S2. Return zero if S1 and S2 are equal.
79 Return some non-zero value otherwise.
80
81 Essentially __memcmpeq has the exact same semantics as memcmp
82 except the return value is less constrained. memcmp is always a
83 correct implementation of __memcmpeq. As well !!memcmp, -memcmp,
84 or bcmp are correct implementations.
85
86 __memcmpeq is meant to be used by compilers when memcmp return is
87 only used for its boolean value.
88
89 __memcmpeq is declared only for use by compilers. Programs should
90 continue to use memcmp. */
91extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n)
92 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
93
94/* Search N bytes of S for C. */
95#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
96extern "C++"
97{
98extern void *memchr (void *__s, int __c, size_t __n)
99 __THROWnoexcept (true) __asm ("memchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
100extern const void *memchr (const void *__s, int __c, size_t __n)
101 __THROWnoexcept (true) __asm ("memchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
102
103# ifdef __OPTIMIZE__1
104__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
void *
105memchr (void *__s, int __c, size_t __n) __THROWnoexcept (true)
106{
107 return __builtin_memchr (__s, __c, __n);
108}
109
110__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
const void *
111memchr (const void *__s, int __c, size_t __n) __THROWnoexcept (true)
112{
113 return __builtin_memchr (__s, __c, __n);
114}
115# endif
116}
117#else
118extern void *memchr (const void *__s, int __c, size_t __n)
119 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
120# if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC
121# define memchr(S, C, N) \
122 __glibc_const_generic (S, const void *, memchr (S, C, N))
123# endif
124#endif
125
126#ifdef __USE_GNU1
127/* Search in S for C. This is similar to `memchr' but there is no
128 length limit. */
129# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
130extern "C++" void *rawmemchr (void *__s, int __c)
131 __THROWnoexcept (true) __asm ("rawmemchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
132extern "C++" const void *rawmemchr (const void *__s, int __c)
133 __THROWnoexcept (true) __asm ("rawmemchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
134# else
135extern void *rawmemchr (const void *__s, int __c)
136 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
137# endif
138
139/* Search N bytes of S for the final occurrence of C. */
140# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
141extern "C++" void *memrchr (void *__s, int __c, size_t __n)
142 __THROWnoexcept (true) __asm ("memrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)))
143 __attr_access ((__read_only__, 1, 3));
144extern "C++" const void *memrchr (const void *__s, int __c, size_t __n)
145 __THROWnoexcept (true) __asm ("memrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)))
146 __attr_access ((__read_only__, 1, 3));
147# else
148extern void *memrchr (const void *__s, int __c, size_t __n)
149 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)))
150 __attr_access ((__read_only__, 1, 3));
151# endif
152#endif
153
154
155/* Copy SRC to DEST. */
156extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
157 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
158/* Copy no more than N characters of SRC to DEST. */
159extern char *strncpy (char *__restrict __dest,
160 const char *__restrict __src, size_t __n)
161 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
162
163/* Append SRC onto DEST. */
164extern char *strcat (char *__restrict __dest, const char *__restrict __src)
165 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
166/* Append no more than N characters from SRC onto DEST. */
167extern char *strncat (char *__restrict __dest, const char *__restrict __src,
168 size_t __n) __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
169
170/* Compare S1 and S2. */
171extern int strcmp (const char *__s1, const char *__s2)
172 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
173/* Compare N characters of S1 and S2. */
174extern int strncmp (const char *__s1, const char *__s2, size_t __n)
175 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
176
177/* Compare the collated forms of S1 and S2. */
178extern int strcoll (const char *__s1, const char *__s2)
179 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
180/* Put a transformation of SRC into no more than N bytes of DEST. */
181extern size_t strxfrm (char *__restrict __dest,
182 const char *__restrict __src, size_t __n)
183 __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))) __attr_access ((__write_only__, 1, 3));
184
185#ifdef __USE_XOPEN2K81
186/* POSIX.1-2008 extended locale interface (see locale.h). */
187# include <bits/types/locale_t.h>
188
189/* Compare the collated forms of S1 and S2, using sorting rules from L. */
190extern int strcoll_l (const char *__s1, const char *__s2, locale_t __l)
191 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2, 3))__attribute__ ((__nonnull__ (1, 2, 3)));
192/* Put a transformation of SRC into no more than N bytes of DEST,
193 using sorting rules from L. */
194extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n,
195 locale_t __l) __THROWnoexcept (true) __nonnull ((2, 4))__attribute__ ((__nonnull__ (2, 4)))
196 __attr_access ((__write_only__, 1, 3));
197#endif
198
199#if (defined __USE_XOPEN_EXTENDED1 || defined __USE_XOPEN2K81 \
200 || __GLIBC_USE (LIB_EXT2)1 || __GLIBC_USE (ISOC23)1)
201/* Duplicate S, returning an identical malloc'd string. */
202extern char *strdup (const char *__s)
203 __THROWnoexcept (true) __attribute_malloc____attribute__ ((__malloc__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
204#endif
205
206/* Return a malloc'd copy of at most N bytes of STRING. The
207 resultant string is terminated even if no null terminator
208 appears before STRING[N]. */
209#if defined __USE_XOPEN2K81 || __GLIBC_USE (LIB_EXT2)1 || __GLIBC_USE (ISOC23)1
210extern char *strndup (const char *__string, size_t __n)
211 __THROWnoexcept (true) __attribute_malloc____attribute__ ((__malloc__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
212#endif
213
214#if defined __USE_GNU1 && defined __GNUC__4
215/* Duplicate S, returning an identical alloca'd string. */
216# define strdupa(s)(__extension__ ({ const char *__old = (s); size_t __len = strlen
(__old) + 1; char *__new = (char *) __builtin_alloca (__len)
; (char *) memcpy (__new, __old, __len); }))
\
217 (__extension__ \
218 ({ \
219 const char *__old = (s); \
220 size_t __len = strlen (__old) + 1; \
221 char *__new = (char *) __builtin_alloca (__len); \
222 (char *) memcpy (__new, __old, __len); \
223 }))
224
225/* Return an alloca'd copy of at most N bytes of string. */
226# define strndupa(s, n)(__extension__ ({ const char *__old = (s); size_t __len = strnlen
(__old, (n)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
\
227 (__extension__ \
228 ({ \
229 const char *__old = (s); \
230 size_t __len = strnlen (__old, (n)); \
231 char *__new = (char *) __builtin_alloca (__len + 1); \
232 __new[__len] = '\0'; \
233 (char *) memcpy (__new, __old, __len); \
234 }))
235#endif
236
237/* Find the first occurrence of C in S. */
238#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
239extern "C++"
240{
241extern char *strchr (char *__s, int __c)
242 __THROWnoexcept (true) __asm ("strchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
243extern const char *strchr (const char *__s, int __c)
244 __THROWnoexcept (true) __asm ("strchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
245
246# ifdef __OPTIMIZE__1
247__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
char *
248strchr (char *__s, int __c) __THROWnoexcept (true)
249{
250 return __builtin_strchr (__s, __c);
251}
252
253__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
const char *
254strchr (const char *__s, int __c) __THROWnoexcept (true)
255{
256 return __builtin_strchr (__s, __c);
257}
258# endif
259}
260#else
261extern char *strchr (const char *__s, int __c)
262 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
263# if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC
264# define strchr(S, C) \
265 __glibc_const_generic (S, const char *, strchr (S, C))
266# endif
267#endif
268/* Find the last occurrence of C in S. */
269#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
270extern "C++"
271{
272extern char *strrchr (char *__s, int __c)
273 __THROWnoexcept (true) __asm ("strrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
274extern const char *strrchr (const char *__s, int __c)
275 __THROWnoexcept (true) __asm ("strrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
276
277# ifdef __OPTIMIZE__1
278__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
char *
279strrchr (char *__s, int __c) __THROWnoexcept (true)
280{
281 return __builtin_strrchr (__s, __c);
6
Value of 'errno' was not checked and may be overwritten by function '__builtin_strrchr'
282}
283
284__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
const char *
285strrchr (const char *__s, int __c) __THROWnoexcept (true)
286{
287 return __builtin_strrchr (__s, __c);
288}
289# endif
290}
291#else
292extern char *strrchr (const char *__s, int __c)
293 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
294# if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC
295# define strrchr(S, C) \
296 __glibc_const_generic (S, const char *, strrchr (S, C))
297# endif
298#endif
299
300#ifdef __USE_MISC1
301/* This function is similar to `strchr'. But it returns a pointer to
302 the closing NUL byte in case C is not found in S. */
303# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
304extern "C++" char *strchrnul (char *__s, int __c)
305 __THROWnoexcept (true) __asm ("strchrnul") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
306extern "C++" const char *strchrnul (const char *__s, int __c)
307 __THROWnoexcept (true) __asm ("strchrnul") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
308# else
309extern char *strchrnul (const char *__s, int __c)
310 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
311# endif
312#endif
313
314/* Return the length of the initial segment of S which
315 consists entirely of characters not in REJECT. */
316extern size_t strcspn (const char *__s, const char *__reject)
317 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
318/* Return the length of the initial segment of S which
319 consists entirely of characters in ACCEPT. */
320extern size_t strspn (const char *__s, const char *__accept)
321 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
322/* Find the first occurrence in S of any character in ACCEPT. */
323#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
324extern "C++"
325{
326extern char *strpbrk (char *__s, const char *__accept)
327 __THROWnoexcept (true) __asm ("strpbrk") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
328extern const char *strpbrk (const char *__s, const char *__accept)
329 __THROWnoexcept (true) __asm ("strpbrk") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
330
331# ifdef __OPTIMIZE__1
332__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
char *
333strpbrk (char *__s, const char *__accept) __THROWnoexcept (true)
334{
335 return __builtin_strpbrk (__s, __accept);
336}
337
338__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
const char *
339strpbrk (const char *__s, const char *__accept) __THROWnoexcept (true)
340{
341 return __builtin_strpbrk (__s, __accept);
342}
343# endif
344}
345#else
346extern char *strpbrk (const char *__s, const char *__accept)
347 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
348# if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC
349# define strpbrk(S, ACCEPT) \
350 __glibc_const_generic (S, const char *, strpbrk (S, ACCEPT))
351# endif
352#endif
353/* Find the first occurrence of NEEDLE in HAYSTACK. */
354#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
355extern "C++"
356{
357extern char *strstr (char *__haystack, const char *__needle)
358 __THROWnoexcept (true) __asm ("strstr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
359extern const char *strstr (const char *__haystack, const char *__needle)
360 __THROWnoexcept (true) __asm ("strstr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
361
362# ifdef __OPTIMIZE__1
363__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
char *
364strstr (char *__haystack, const char *__needle) __THROWnoexcept (true)
365{
366 return __builtin_strstr (__haystack, __needle);
367}
368
369__extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__))
const char *
370strstr (const char *__haystack, const char *__needle) __THROWnoexcept (true)
371{
372 return __builtin_strstr (__haystack, __needle);
373}
374# endif
375}
376#else
377extern char *strstr (const char *__haystack, const char *__needle)
378 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
379# if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC
380# define strstr(HAYSTACK, NEEDLE) \
381 __glibc_const_generic (HAYSTACK, const char *, \
382 strstr (HAYSTACK, NEEDLE))
383# endif
384#endif
385
386
387/* Divide S into tokens separated by characters in DELIM. */
388extern char *strtok (char *__restrict __s, const char *__restrict __delim)
389 __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2)));
390
391/* Divide S into tokens separated by characters in DELIM. Information
392 passed between calls are stored in SAVE_PTR. */
393extern char *__strtok_r (char *__restrict __s,
394 const char *__restrict __delim,
395 char **__restrict __save_ptr)
396 __THROWnoexcept (true) __nonnull ((2, 3))__attribute__ ((__nonnull__ (2, 3)));
397#ifdef __USE_POSIX1
398extern char *strtok_r (char *__restrict __s, const char *__restrict __delim,
399 char **__restrict __save_ptr)
400 __THROWnoexcept (true) __nonnull ((2, 3))__attribute__ ((__nonnull__ (2, 3)));
401#endif
402
403#ifdef __USE_MISC1
404/* Similar to `strstr' but this function ignores the case of both strings. */
405# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
406extern "C++" char *strcasestr (char *__haystack, const char *__needle)
407 __THROWnoexcept (true) __asm ("strcasestr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
408extern "C++" const char *strcasestr (const char *__haystack,
409 const char *__needle)
410 __THROWnoexcept (true) __asm ("strcasestr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
411# else
412extern char *strcasestr (const char *__haystack, const char *__needle)
413 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
414# endif
415#endif
416
417#ifdef __USE_MISC1
418/* Find the first occurrence of NEEDLE in HAYSTACK.
419 NEEDLE is NEEDLELEN bytes long;
420 HAYSTACK is HAYSTACKLEN bytes long. */
421extern void *memmem (const void *__haystack, size_t __haystacklen,
422 const void *__needle, size_t __needlelen)
423 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 3))__attribute__ ((__nonnull__ (1, 3)))
424 __attr_access ((__read_only__, 1, 2))
425 __attr_access ((__read_only__, 3, 4));
426
427/* Copy N bytes of SRC to DEST, return pointer to bytes after the
428 last written byte. */
429extern void *__mempcpy (void *__restrict __dest,
430 const void *__restrict __src, size_t __n)
431 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
432extern void *mempcpy (void *__restrict __dest,
433 const void *__restrict __src, size_t __n)
434 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
435#endif
436
437
438/* Return the length of S. */
439extern size_t strlen (const char *__s)
440 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
441
442#ifdef __USE_XOPEN2K81
443/* Find the length of STRING, but scan at most MAXLEN characters.
444 If no '\0' terminator is found in that many characters, return MAXLEN. */
445extern size_t strnlen (const char *__string, size_t __maxlen)
446 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
447#endif
448
449
450/* Return a string describing the meaning of the `errno' code in ERRNUM. */
451extern char *strerror (int __errnum) __THROWnoexcept (true);
452#ifdef __USE_XOPEN2K1
453/* Reentrant version of `strerror'.
454 There are 2 flavors of `strerror_r', GNU which returns the string
455 and may or may not use the supplied temporary buffer and POSIX one
456 which fills the string into the buffer.
457 To use the POSIX version, -D_XOPEN_SOURCE=600 or -D_POSIX_C_SOURCE=200112L
458 without -D_GNU_SOURCE is needed, otherwise the GNU version is
459 preferred. */
460# if defined __USE_XOPEN2K1 && !defined __USE_GNU1
461/* Fill BUF with a string describing the meaning of the `errno' code in
462 ERRNUM. */
463# ifdef __REDIRECT_NTH
464extern int __REDIRECT_NTH (strerror_r,strerror_r (int __errnum, char *__buf, size_t __buflen) noexcept
(true) __asm__ ("" "__xpg_strerror_r")
465 (int __errnum, char *__buf, size_t __buflen),strerror_r (int __errnum, char *__buf, size_t __buflen) noexcept
(true) __asm__ ("" "__xpg_strerror_r")
466 __xpg_strerror_r)strerror_r (int __errnum, char *__buf, size_t __buflen) noexcept
(true) __asm__ ("" "__xpg_strerror_r")
__nonnull ((2))__attribute__ ((__nonnull__ (2)))
467 __attr_access ((__write_only__, 2, 3));
468# else
469extern int __xpg_strerror_r (int __errnum, char *__buf, size_t __buflen)
470 __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))) __attr_access ((__write_only__, 2, 3));
471# define strerror_r __xpg_strerror_r
472# endif
473# else
474/* If a temporary buffer is required, at most BUFLEN bytes of BUF will be
475 used. */
476extern char *strerror_r (int __errnum, char *__buf, size_t __buflen)
477 __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))) __wur__attribute__ ((__warn_unused_result__)) __attr_access ((__write_only__, 2, 3));
478# endif
479
480# ifdef __USE_GNU1
481/* Return a string describing the meaning of tthe error in ERR. */
482extern const char *strerrordesc_np (int __err) __THROWnoexcept (true);
483/* Return a string with the error name in ERR. */
484extern const char *strerrorname_np (int __err) __THROWnoexcept (true);
485# endif
486#endif
487
488#ifdef __USE_XOPEN2K81
489/* Translate error number to string according to the locale L. */
490extern char *strerror_l (int __errnum, locale_t __l) __THROWnoexcept (true);
491#endif
492
493#ifdef __USE_MISC1
494# include <strings.h>
495
496/* Set N bytes of S to 0. The compiler will not delete a call to this
497 function, even if S is dead after the call. */
498extern void explicit_bzero (void *__s, size_t __n) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1)))
499 __fortified_attr_access (__write_only__, 1, 2);
500
501/* Return the next DELIM-delimited token from *STRINGP,
502 terminating it with a '\0', and update *STRINGP to point past it. */
503extern char *strsep (char **__restrict __stringp,
504 const char *__restrict __delim)
505 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
506#endif
507
508#ifdef __USE_XOPEN2K81
509/* Return a string describing the meaning of the signal number in SIG. */
510extern char *strsignal (int __sig) __THROWnoexcept (true);
511
512# ifdef __USE_GNU1
513/* Return an abbreviation string for the signal number SIG. */
514extern const char *sigabbrev_np (int __sig) __THROWnoexcept (true);
515/* Return a string describing the meaning of the signal number in SIG,
516 the result is not translated. */
517extern const char *sigdescr_np (int __sig) __THROWnoexcept (true);
518# endif
519
520/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
521extern char *__stpcpy (char *__restrict __dest, const char *__restrict __src)
522 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
523extern char *stpcpy (char *__restrict __dest, const char *__restrict __src)
524 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
525
526/* Copy no more than N characters of SRC to DEST, returning the address of
527 the last character written into DEST. */
528extern char *__stpncpy (char *__restrict __dest,
529 const char *__restrict __src, size_t __n)
530 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
531extern char *stpncpy (char *__restrict __dest,
532 const char *__restrict __src, size_t __n)
533 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
534#endif
535
536#ifdef __USE_MISC1
537/* Copy at most N - 1 characters from SRC to DEST. */
538extern size_t strlcpy (char *__restrict __dest,
539 const char *__restrict __src, size_t __n)
540 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))) __attr_access ((__write_only__, 1, 3));
541
542/* Append SRC to DEST, possibly with truncation to keep the total size
543 below N. */
544extern size_t strlcat (char *__restrict __dest,
545 const char *__restrict __src, size_t __n)
546 __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))) __attr_access ((__read_write__, 1, 3));
547#endif
548
549#ifdef __USE_GNU1
550/* Compare S1 and S2 as strings holding name & indices/version numbers. */
551extern int strverscmp (const char *__s1, const char *__s2)
552 __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2)));
553
554/* Sautee STRING briskly. */
555extern char *strfry (char *__string) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
556
557/* Frobnicate N bytes of S. */
558extern void *memfrob (void *__s, size_t __n) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1)))
559 __attr_access ((__read_write__, 1, 2));
560
561# ifndef basename
562/* Return the file name within directory of FILENAME. We don't
563 declare the function if the `basename' macro is available (defined
564 in <libgen.h>) which makes the XPG version of this function
565 available. */
566# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
567extern "C++" char *basename (char *__filename)
568 __THROWnoexcept (true) __asm ("basename") __nonnull ((1))__attribute__ ((__nonnull__ (1)));
569extern "C++" const char *basename (const char *__filename)
570 __THROWnoexcept (true) __asm ("basename") __nonnull ((1))__attribute__ ((__nonnull__ (1)));
571# else
572extern char *basename (const char *__filename) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1)));
573# endif
574# endif
575#endif
576
577#if __GNUC_PREREQ (3,4)((4 << 16) + 2 >= ((3) << 16) + (4))
578# if __USE_FORTIFY_LEVEL2 > 0 && defined __fortify_functionextern __inline __attribute__ ((__always_inline__)) __attribute__
((__gnu_inline__)) __attribute__ ((__artificial__))
579/* Functions with security checks. */
580# include <bits/string_fortified.h>
581# endif
582#endif
583
584__END_DECLS}
585
586#endif /* string.h */