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