]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/compiler-rt/lib/scudo/standalone/string_utils.cc
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / compiler-rt / lib / scudo / standalone / string_utils.cc
1 //===-- string_utils.cc -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "string_utils.h"
10 #include "common.h"
11
12 #include <ctype.h>
13 #include <stdarg.h>
14 #include <string.h>
15
16 namespace scudo {
17
18 static int appendChar(char **Buffer, const char *BufferEnd, char C) {
19   if (*Buffer < BufferEnd) {
20     **Buffer = C;
21     (*Buffer)++;
22   }
23   return 1;
24 }
25
26 // Appends number in a given Base to buffer. If its length is less than
27 // |MinNumberLength|, it is padded with leading zeroes or spaces, depending
28 // on the value of |PadWithZero|.
29 static int appendNumber(char **Buffer, const char *BufferEnd, u64 AbsoluteValue,
30                         u8 Base, u8 MinNumberLength, bool PadWithZero,
31                         bool Negative, bool Upper) {
32   constexpr uptr MaxLen = 30;
33   RAW_CHECK(Base == 10 || Base == 16);
34   RAW_CHECK(Base == 10 || !Negative);
35   RAW_CHECK(AbsoluteValue || !Negative);
36   RAW_CHECK(MinNumberLength < MaxLen);
37   int Res = 0;
38   if (Negative && MinNumberLength)
39     --MinNumberLength;
40   if (Negative && PadWithZero)
41     Res += appendChar(Buffer, BufferEnd, '-');
42   uptr NumBuffer[MaxLen];
43   int Pos = 0;
44   do {
45     RAW_CHECK_MSG(static_cast<uptr>(Pos) < MaxLen,
46                   "appendNumber buffer overflow");
47     NumBuffer[Pos++] = AbsoluteValue % Base;
48     AbsoluteValue /= Base;
49   } while (AbsoluteValue > 0);
50   if (Pos < MinNumberLength) {
51     memset(&NumBuffer[Pos], 0,
52            sizeof(NumBuffer[0]) * static_cast<uptr>(MinNumberLength - Pos));
53     Pos = MinNumberLength;
54   }
55   RAW_CHECK(Pos > 0);
56   Pos--;
57   for (; Pos >= 0 && NumBuffer[Pos] == 0; Pos--) {
58     char c = (PadWithZero || Pos == 0) ? '0' : ' ';
59     Res += appendChar(Buffer, BufferEnd, c);
60   }
61   if (Negative && !PadWithZero)
62     Res += appendChar(Buffer, BufferEnd, '-');
63   for (; Pos >= 0; Pos--) {
64     char Digit = static_cast<char>(NumBuffer[Pos]);
65     Digit = static_cast<char>((Digit < 10) ? '0' + Digit
66                                            : (Upper ? 'A' : 'a') + Digit - 10);
67     Res += appendChar(Buffer, BufferEnd, Digit);
68   }
69   return Res;
70 }
71
72 static int appendUnsigned(char **Buffer, const char *BufferEnd, u64 Num,
73                           u8 Base, u8 MinNumberLength, bool PadWithZero,
74                           bool Upper) {
75   return appendNumber(Buffer, BufferEnd, Num, Base, MinNumberLength,
76                       PadWithZero, /*Negative=*/false, Upper);
77 }
78
79 static int appendSignedDecimal(char **Buffer, const char *BufferEnd, s64 Num,
80                                u8 MinNumberLength, bool PadWithZero) {
81   const bool Negative = (Num < 0);
82   return appendNumber(Buffer, BufferEnd,
83                       static_cast<u64>(Negative ? -Num : Num), 10,
84                       MinNumberLength, PadWithZero, Negative,
85                       /*Upper=*/false);
86 }
87
88 // Use the fact that explicitly requesting 0 Width (%0s) results in UB and
89 // interpret Width == 0 as "no Width requested":
90 // Width == 0 - no Width requested
91 // Width  < 0 - left-justify S within and pad it to -Width chars, if necessary
92 // Width  > 0 - right-justify S, not implemented yet
93 static int appendString(char **Buffer, const char *BufferEnd, int Width,
94                         int MaxChars, const char *S) {
95   if (!S)
96     S = "<null>";
97   int Res = 0;
98   for (; *S; S++) {
99     if (MaxChars >= 0 && Res >= MaxChars)
100       break;
101     Res += appendChar(Buffer, BufferEnd, *S);
102   }
103   // Only the left justified strings are supported.
104   while (Width < -Res)
105     Res += appendChar(Buffer, BufferEnd, ' ');
106   return Res;
107 }
108
109 static int appendPointer(char **Buffer, const char *BufferEnd, u64 ptr_value) {
110   int Res = 0;
111   Res += appendString(Buffer, BufferEnd, 0, -1, "0x");
112   Res += appendUnsigned(Buffer, BufferEnd, ptr_value, 16,
113                         SCUDO_POINTER_FORMAT_LENGTH, /*PadWithZero=*/true,
114                         /*Upper=*/false);
115   return Res;
116 }
117
118 int formatString(char *Buffer, uptr BufferLength, const char *Format,
119                  va_list Args) {
120   UNUSED static const char *PrintfFormatsHelp =
121       "Supported formatString formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; "
122       "%[-]([0-9]*)?(\\.\\*)?s; %c\n";
123   RAW_CHECK(Format);
124   RAW_CHECK(BufferLength > 0);
125   const char *BufferEnd = &Buffer[BufferLength - 1];
126   const char *Cur = Format;
127   int Res = 0;
128   for (; *Cur; Cur++) {
129     if (*Cur != '%') {
130       Res += appendChar(&Buffer, BufferEnd, *Cur);
131       continue;
132     }
133     Cur++;
134     const bool LeftJustified = *Cur == '-';
135     if (LeftJustified)
136       Cur++;
137     bool HaveWidth = (*Cur >= '0' && *Cur <= '9');
138     const bool PadWithZero = (*Cur == '0');
139     u8 Width = 0;
140     if (HaveWidth) {
141       while (*Cur >= '0' && *Cur <= '9')
142         Width = static_cast<u8>(Width * 10 + *Cur++ - '0');
143     }
144     const bool HavePrecision = (Cur[0] == '.' && Cur[1] == '*');
145     int Precision = -1;
146     if (HavePrecision) {
147       Cur += 2;
148       Precision = va_arg(Args, int);
149     }
150     const bool HaveZ = (*Cur == 'z');
151     Cur += HaveZ;
152     const bool HaveLL = !HaveZ && (Cur[0] == 'l' && Cur[1] == 'l');
153     Cur += HaveLL * 2;
154     s64 DVal;
155     u64 UVal;
156     const bool HaveLength = HaveZ || HaveLL;
157     const bool HaveFlags = HaveWidth || HaveLength;
158     // At the moment only %s supports precision and left-justification.
159     CHECK(!((Precision >= 0 || LeftJustified) && *Cur != 's'));
160     switch (*Cur) {
161     case 'd': {
162       DVal = HaveLL ? va_arg(Args, s64)
163                     : HaveZ ? va_arg(Args, sptr) : va_arg(Args, int);
164       Res += appendSignedDecimal(&Buffer, BufferEnd, DVal, Width, PadWithZero);
165       break;
166     }
167     case 'u':
168     case 'x':
169     case 'X': {
170       UVal = HaveLL ? va_arg(Args, u64)
171                     : HaveZ ? va_arg(Args, uptr) : va_arg(Args, unsigned);
172       const bool Upper = (*Cur == 'X');
173       Res += appendUnsigned(&Buffer, BufferEnd, UVal, (*Cur == 'u') ? 10 : 16,
174                             Width, PadWithZero, Upper);
175       break;
176     }
177     case 'p': {
178       RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);
179       Res += appendPointer(&Buffer, BufferEnd, va_arg(Args, uptr));
180       break;
181     }
182     case 's': {
183       RAW_CHECK_MSG(!HaveLength, PrintfFormatsHelp);
184       // Only left-justified Width is supported.
185       CHECK(!HaveWidth || LeftJustified);
186       Res += appendString(&Buffer, BufferEnd, LeftJustified ? -Width : Width,
187                           Precision, va_arg(Args, char *));
188       break;
189     }
190     case 'c': {
191       RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);
192       Res +=
193           appendChar(&Buffer, BufferEnd, static_cast<char>(va_arg(Args, int)));
194       break;
195     }
196     case '%': {
197       RAW_CHECK_MSG(!HaveFlags, PrintfFormatsHelp);
198       Res += appendChar(&Buffer, BufferEnd, '%');
199       break;
200     }
201     default: {
202       RAW_CHECK_MSG(false, PrintfFormatsHelp);
203     }
204     }
205   }
206   RAW_CHECK(Buffer <= BufferEnd);
207   appendChar(&Buffer, BufferEnd + 1, '\0');
208   return Res;
209 }
210
211 void ScopedString::append(const char *Format, va_list Args) {
212   CHECK_LT(Length, String.size());
213   formatString(String.data() + Length, String.size() - Length, Format, Args);
214   Length += strlen(String.data() + Length);
215   CHECK_LT(Length, String.size());
216 }
217
218 FORMAT(2, 3)
219 void ScopedString::append(const char *Format, ...) {
220   va_list Args;
221   va_start(Args, Format);
222   append(Format, Args);
223   va_end(Args);
224 }
225
226 FORMAT(1, 2)
227 void Printf(const char *Format, ...) {
228   va_list Args;
229   va_start(Args, Format);
230   ScopedString Msg(512);
231   Msg.append(Format, Args);
232   outputRaw(Msg.data());
233   va_end(Args);
234 }
235
236 } // namespace scudo