/src/openssl/crypto/bio/bio_print.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * |
4 | | * Licensed under the Apache License 2.0 (the "License"). You may not use |
5 | | * this file except in compliance with the License. You can obtain a copy |
6 | | * in the file LICENSE in the source distribution or at |
7 | | * https://www.openssl.org/source/license.html |
8 | | */ |
9 | | |
10 | | #include <stdio.h> |
11 | | #include <string.h> |
12 | | #include "internal/cryptlib.h" |
13 | | #include "crypto/ctype.h" |
14 | | #include "internal/numbers.h" |
15 | | #include <openssl/bio.h> |
16 | | #include <openssl/configuration.h> |
17 | | |
18 | | int BIO_printf(BIO *bio, const char *format, ...) |
19 | 0 | { |
20 | 0 | va_list args; |
21 | 0 | int ret; |
22 | |
|
23 | 0 | va_start(args, format); |
24 | |
|
25 | 0 | ret = BIO_vprintf(bio, format, args); |
26 | |
|
27 | 0 | va_end(args); |
28 | 0 | return ret; |
29 | 0 | } |
30 | | |
31 | | #if defined(_WIN32) |
32 | | /* |
33 | | * _MSC_VER described here: |
34 | | * https://learn.microsoft.com/en-us/cpp/overview/compiler-versions?view=msvc-170 |
35 | | * |
36 | | * Beginning with the UCRT in Visual Studio 2015 and Windows 10, snprintf is no |
37 | | * longer identical to _snprintf. The snprintf behavior is now C99 standard |
38 | | * conformant. The difference is that if you run out of buffer, snprintf |
39 | | * null-terminates the end of the buffer and returns the number of characters |
40 | | * that would have been required whereas _snprintf doesn't null-terminate the |
41 | | * buffer and returns -1. Also, snprintf() includes one more character in the |
42 | | * output because it doesn't null-terminate the buffer. |
43 | | * [ https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/snprintf-snprintf-snprintf-l-snwprintf-snwprintf-l?view=msvc-170#remarks |
44 | | * |
45 | | * for older MSVC (older than 2015) we can use _vscprintf() and _vsnprintf() |
46 | | * as suggested here: |
47 | | * https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 |
48 | | * |
49 | | */ |
50 | | static int msvc_bio_vprintf(BIO *bio, const char *format, va_list args) |
51 | | { |
52 | | char buf[512]; |
53 | | char *abuf; |
54 | | int ret, sz; |
55 | | |
56 | | sz = _vsnprintf_s(buf, sizeof(buf), _TRUNCATE, format, args); |
57 | | if (sz == -1) { |
58 | | sz = _vscprintf(format, args) + 1; |
59 | | abuf = (char *)OPENSSL_malloc(sz); |
60 | | if (abuf == NULL) { |
61 | | ret = -1; |
62 | | } else { |
63 | | sz = _vsnprintf(abuf, sz, format, args); |
64 | | ret = BIO_write(bio, abuf, sz); |
65 | | OPENSSL_free(abuf); |
66 | | } |
67 | | } else { |
68 | | ret = BIO_write(bio, buf, sz); |
69 | | } |
70 | | |
71 | | return ret; |
72 | | } |
73 | | |
74 | | /* |
75 | | * This function is for unit test on windows only when built with Visual Studio |
76 | | */ |
77 | | int ossl_BIO_snprintf_msvc(char *buf, size_t n, const char *format, ...) |
78 | | { |
79 | | va_list args; |
80 | | int ret; |
81 | | |
82 | | va_start(args, format); |
83 | | ret = _vsnprintf_s(buf, n, _TRUNCATE, format, args); |
84 | | va_end(args); |
85 | | |
86 | | return ret; |
87 | | } |
88 | | |
89 | | #endif |
90 | | |
91 | | int BIO_vprintf(BIO *bio, const char *format, va_list args) |
92 | 0 | { |
93 | 0 | va_list cp_args; |
94 | 0 | #if !defined(_MSC_VER) || _MSC_VER > 1900 |
95 | 0 | int sz; |
96 | 0 | #endif |
97 | 0 | int ret = -1; |
98 | |
|
99 | 0 | va_copy(cp_args, args); |
100 | | #if defined(_MSC_VER) && _MSC_VER < 1900 |
101 | | ret = msvc_bio_vprintf(bio, format, cp_args); |
102 | | #else |
103 | 0 | char buf[512]; |
104 | 0 | char *abuf; |
105 | | /* |
106 | | * some compilers modify va_list, hence each call to v*printf() |
107 | | * should operate with its own instance of va_list. The first |
108 | | * call to vsnprintf() here uses args we got in function argument. |
109 | | * The second call is going to use cp_args we made earlier. |
110 | | */ |
111 | 0 | sz = vsnprintf(buf, sizeof(buf), format, args); |
112 | 0 | if (sz >= 0) { |
113 | 0 | if ((size_t)sz > sizeof(buf)) { |
114 | 0 | sz += 1; |
115 | 0 | abuf = (char *)OPENSSL_malloc(sz); |
116 | 0 | if (abuf == NULL) { |
117 | 0 | ret = -1; |
118 | 0 | } else { |
119 | 0 | sz = vsnprintf(abuf, sz, format, cp_args); |
120 | 0 | ret = BIO_write(bio, abuf, sz); |
121 | 0 | OPENSSL_free(abuf); |
122 | 0 | } |
123 | 0 | } else { |
124 | | /* vsnprintf returns length not including nul-terminator */ |
125 | 0 | ret = BIO_write(bio, buf, sz); |
126 | 0 | } |
127 | 0 | } |
128 | 0 | #endif |
129 | 0 | va_end(cp_args); |
130 | 0 | return ret; |
131 | 0 | } |
132 | | |
133 | | /* |
134 | | * For historical reasons BIO_snprintf and friends return a failure for string |
135 | | * truncation (-1) instead of the POSIX requirement of a success with the |
136 | | * number of characters that would have been written. Upon seeing -1 on |
137 | | * return, the caller must treat output buf as unsafe (as a buf with missing |
138 | | * nul terminator). |
139 | | */ |
140 | | int BIO_snprintf(char *buf, size_t n, const char *format, ...) |
141 | 5.48k | { |
142 | 5.48k | va_list args; |
143 | 5.48k | int ret; |
144 | | |
145 | 5.48k | va_start(args, format); |
146 | | |
147 | | #if defined(_MSC_VER) && _MSC_VER < 1900 |
148 | | ret = _vsnprintf_s(buf, n, _TRUNCATE, format, args); |
149 | | #else |
150 | 5.48k | ret = vsnprintf(buf, n, format, args); |
151 | 5.48k | if ((size_t)ret >= n) |
152 | 0 | ret = -1; |
153 | 5.48k | #endif |
154 | 5.48k | va_end(args); |
155 | | |
156 | 5.48k | return ret; |
157 | 5.48k | } |
158 | | |
159 | | int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) |
160 | 1.09k | { |
161 | 1.09k | int ret; |
162 | | |
163 | | #if defined(_MSC_VER) && _MSC_VER < 1900 |
164 | | ret = _vsnprintf_s(buf, n, _TRUNCATE, format, args); |
165 | | #else |
166 | 1.09k | ret = vsnprintf(buf, n, format, args); |
167 | 1.09k | if ((size_t)ret >= n) |
168 | 0 | ret = -1; |
169 | 1.09k | #endif |
170 | 1.09k | return ret; |
171 | 1.09k | } |