1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2024, Synopsys Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 #define __STDC_WANT_LIB_EXT1__ 1
36 #include "stdio_private.h"
37 #include <stdio.h>
38 #include <stddef.h>
39 #include <stdbool.h>
40 #include "../stdlib/local_s.h"
41
42 int
sprintf_s(char * restrict s,rsize_t bufsize,const char * restrict fmt,...)43 sprintf_s(char *restrict s, rsize_t bufsize, const char *restrict fmt, ...)
44 {
45 bool write_null = true;
46 const char *msg = "";
47 va_list args;
48 int rc;
49
50 if (s == NULL) {
51 write_null = false;
52 msg = "sprintf_s: dest buffer is null";
53 goto handle_error;
54 } else if ((bufsize == 0) || (CHECK_RSIZE(bufsize))) {
55 write_null = false;
56 msg = "sprintf_s: invalid buffer size";
57 goto handle_error;
58 } else if (fmt == NULL) {
59 msg = "sprintf_s: null format string";
60 goto handle_error;
61 } else if (strstr(fmt, " %n") != NULL) {
62 msg = "sprintf_s: format string contains percent-n";
63 goto handle_error;
64 } else {
65 va_start(args, fmt);
66
67 va_list args_copy;
68 va_copy(args_copy, args);
69
70 const char *check_ptr = fmt;
71 uint8_t null_str = 0;
72 while (*check_ptr && null_str == 0) {
73 if (check_ptr[0] == '%') {
74 switch (check_ptr[1]) {
75 case 's': {
76 char *str_arg = va_arg(args_copy, char *);
77 if (str_arg == NULL) {
78 msg = "sprintf_s: null string argument";
79 va_end(args_copy);
80 va_end(args);
81 null_str = 1;
82 goto handle_error;
83 }
84 break;
85 }
86 case 'd':
87 case 'i':
88 case 'u':
89 case 'o':
90 case 'x':
91 case 'X':
92 case 'c':
93 case 'h':
94 case 'l':
95 case 'L':
96 case 'z':
97 case 't':
98 va_arg(args_copy, int);
99 break;
100 case 'f':
101 case 'F':
102 case 'e':
103 case 'E':
104 case 'g':
105 case 'G':
106 case 'a':
107 case 'A':
108 va_arg(args_copy, double);
109 break;
110 case 'p':
111 va_arg(args_copy, void *);
112 break;
113 default:
114 break;
115 }
116 }
117 check_ptr++;
118 }
119
120 rc = vsnprintf(s, bufsize, fmt, args);
121 va_end(args_copy);
122 va_end(args);
123 }
124
125 if (rc < 0 || rc >= (int)bufsize) {
126 msg = "sprintf_s: dest buffer overflow";
127 goto handle_error;
128 } else {
129 s[rc] = 0;
130 }
131
132 // Normal return path
133 return rc;
134
135 handle_error:
136 if (__cur_handler != NULL) {
137 __cur_handler(msg, NULL, -1);
138 }
139
140 rc = 0; /* standard stipulates this */
141
142 if (write_null && s != NULL) {
143 s[0] = '\0'; /* again, standard requires this */
144 }
145
146 return rc;
147 }
148