github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/native/thrift_skip.c (about) 1 /** 2 * Copyright 2023 CloudWeGo Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdint.h> 18 #include "test/xprintf.h" 19 20 #define ETAG -1 21 #define EEOF -2 22 #define ESTACK -3 23 #define MAX_STACK 1024 24 25 #define T_bool 2 26 #define T_i8 3 27 #define T_double 4 28 #define T_i16 6 29 #define T_i32 8 30 #define T_i64 10 31 #define T_string 11 32 #define T_struct 12 33 #define T_map 13 34 #define T_set 14 35 #define T_list 15 36 #define T_list_elem 0xfe 37 #define T_map_pair 0xff 38 39 typedef struct 40 { 41 uint8_t t; 42 uint8_t k; 43 uint8_t v; 44 uint32_t n; 45 } skipbuf_t; 46 47 static const char WireTags[256] = { 48 [T_bool] = 1, 49 [T_i8] = 1, 50 [T_double] = 1, 51 [T_i16] = 1, 52 [T_i32] = 1, 53 [T_i64] = 1, 54 [T_string] = 1, 55 [T_struct] = 1, 56 [T_map] = 1, 57 [T_set] = 1, 58 [T_list] = 1, 59 }; 60 61 static const int8_t SkipSizeFixed[256] = { 62 [T_bool] = 1, 63 [T_i8] = 1, 64 [T_double] = 8, 65 [T_i16] = 2, 66 [T_i32] = 4, 67 [T_i64] = 8, 68 }; 69 70 static inline int64_t u32be(const char *s) 71 { 72 return __builtin_bswap32(*(const uint32_t *)s); 73 } 74 75 static inline int64_t u16be(const char *s) 76 { 77 return __builtin_bswap16(*(const uint16_t *)s); 78 } 79 80 static inline char stpop(skipbuf_t *s, int64_t *p) 81 { 82 if (s[*p].n == 0) 83 { 84 (*p)--; 85 return 1; 86 } 87 else 88 { 89 s[*p].n--; 90 return 0; 91 } 92 } 93 94 static inline char stadd(skipbuf_t *s, int64_t *p, uint8_t t) 95 { 96 if (++*p >= MAX_STACK) 97 { 98 return 0; 99 } 100 else 101 { 102 s[*p].t = t; 103 s[*p].n = 0; 104 return 1; 105 } 106 } 107 108 static inline void mvbuf(const char **s, int64_t *n, int64_t *r, int64_t nb) 109 { 110 *n -= nb; 111 *r += nb; 112 *s += nb; 113 } 114 115 int64_t tb_skip(skipbuf_t *st, const char *s, int64_t n, uint8_t t) 116 { 117 int64_t nb; 118 int64_t rv = 0; 119 int64_t sp = 0; 120 121 /* initialize the stack */ 122 st->n = 0; 123 st->t = t; 124 125 /* run until drain */ 126 while (sp >= 0) 127 { 128 xprintf("[T_%d] sp:%d, rv:%d, st:{t:%d, k:%d, e:%d, n:%d}\n", st[sp].t, sp, rv, st[sp].t, st[sp].k, st[sp].v, st[sp].n); 129 // xprintf("[T_%d] sp:%d, rv:%d\n", st[sp].t, sp, rv); 130 switch (st[sp].t) 131 { 132 default: 133 { 134 return ETAG; 135 } 136 137 /* simple fixed types */ 138 case T_bool: 139 case T_i8: 140 case T_double: 141 case T_i16: 142 case T_i32: 143 case T_i64: 144 { 145 if ((nb = SkipSizeFixed[st[sp].t]) > n) 146 { 147 return EEOF; 148 } 149 else 150 { 151 stpop(st, &sp); 152 mvbuf(&s, &n, &rv, nb); 153 break; 154 } 155 } 156 157 /* strings & binaries */ 158 case T_string: 159 { 160 if (n < 4) 161 { 162 return EEOF; 163 } 164 else if ((nb = u32be(s) + 4) > n) 165 { 166 return EEOF; 167 } 168 else 169 { 170 stpop(st, &sp); 171 mvbuf(&s, &n, &rv, nb); 172 break; 173 } 174 } 175 176 /* structs */ 177 case T_struct: 178 { 179 int64_t nf; 180 uint8_t vt; 181 182 /* must have at least 1 byte */ 183 if (n < 1) 184 { 185 return EEOF; 186 } 187 188 /* check for end of tag */ 189 if ((vt = *s) == 0) 190 { 191 stpop(st, &sp); 192 mvbuf(&s, &n, &rv, 1); 193 continue; 194 } 195 196 xprintf("[T_struct] rv:%d, ft:%d, fid:%d\n", rv + 3, vt, u16be(s + 1)); 197 198 /* check for tag value */ 199 if (!(WireTags[vt])) 200 { 201 return ETAG; 202 } 203 204 /* fast-path for primitive fields */ 205 if ((nf = SkipSizeFixed[vt]) != 0) 206 { 207 if (n < nf + 3) 208 { 209 return EEOF; 210 } 211 else 212 { 213 mvbuf(&s, &n, &rv, nf + 3); 214 continue; 215 } 216 } 217 218 /* must have more than 3 bytes (fields cannot have a size of zero), also skip the field ID cause we don't care */ 219 if (n <= 3) 220 { 221 return EEOF; 222 } 223 else if (!stadd(st, &sp, vt)) 224 { 225 return ESTACK; 226 } 227 else 228 { 229 mvbuf(&s, &n, &rv, 3); 230 break; 231 } 232 } 233 234 /* maps */ 235 case T_map: 236 { 237 int64_t np; 238 uint8_t kt; 239 uint8_t vt; 240 241 /* must have at least 6 bytes */ 242 if (n < 6) 243 { 244 return EEOF; 245 } 246 247 /* get the element type and count */ 248 kt = s[0]; 249 vt = s[1]; 250 np = u32be(s + 2); 251 xprintf("[T_map] header rv:%d, kt:%d, vt:%d, np:%d\n", rv + 6, kt, vt, np); 252 253 /* check for tag value */ 254 if (!(WireTags[kt] && WireTags[vt])) 255 { 256 return ETAG; 257 } 258 259 /* empty map */ 260 if (np == 0) 261 { 262 stpop(st, &sp); 263 mvbuf(&s, &n, &rv, 6); 264 continue; 265 } 266 267 /* check for fixed key and value */ 268 int64_t nk = SkipSizeFixed[kt]; 269 int64_t nv = SkipSizeFixed[vt]; 270 271 /* fast path for fixed key and value */ 272 if (nk != 0 && nv != 0) 273 { 274 if ((nb = np * (nk + nv) + 6) > n) 275 { 276 return EEOF; 277 } 278 else 279 { 280 stpop(st, &sp); 281 mvbuf(&s, &n, &rv, nb); 282 continue; 283 } 284 } 285 286 /* set to parse the map pairs */ 287 st[sp].k = kt; 288 st[sp].v = vt; 289 st[sp].t = T_map_pair; 290 st[sp].n = np * 2 - 1; 291 mvbuf(&s, &n, &rv, 6); 292 break; 293 } 294 295 /* map pairs */ 296 case T_map_pair: 297 { 298 uint8_t kt = st[sp].k; 299 uint8_t vt = st[sp].v; 300 301 /* there are keys pending */ 302 if (!stpop(st, &sp)) 303 { 304 if ((st[sp].n & 1) == 0) 305 { 306 xprintf("[T_map] key rv:%d, i:%d\n", rv, st[sp].n / 2); 307 vt = kt; 308 } 309 else 310 { 311 xprintf("[T_map] elem rv:%d, i:%d\n", rv, st[sp].n / 2); 312 } 313 } 314 else 315 { 316 xprintf("[T_map] elem rv:%d, i:%d\n", rv, st[sp].n / 2); 317 } 318 /* push the element onto stack */ 319 if (stadd(st, &sp, vt)) 320 { 321 break; 322 } 323 else 324 { 325 return ESTACK; 326 } 327 } 328 329 /* sets and lists */ 330 case T_set: 331 case T_list: 332 { 333 int64_t nv; 334 int64_t nt; 335 uint8_t et; 336 337 /* must have at least 5 bytes */ 338 if (n < 5) 339 { 340 return EEOF; 341 } 342 343 /* get the element type and count */ 344 et = s[0]; 345 nv = u32be(s + 1); 346 xprintf("[T_list] header rv:%d, et:%d, np:%d\n", rv + 5, et, nv); 347 348 /* check for tag value */ 349 if (!(WireTags[et])) 350 { 351 return ETAG; 352 } 353 354 /* empty sequence */ 355 if (nv == 0) 356 { 357 stpop(st, &sp); 358 mvbuf(&s, &n, &rv, 5); 359 continue; 360 } 361 362 /* fast path for fixed types */ 363 if ((nt = SkipSizeFixed[et]) != 0) 364 { 365 if ((nb = nv * nt + 5) > n) 366 { 367 return EEOF; 368 } 369 else 370 { 371 xprintf("[T_list] elem rv:%d, i:%d\n", rv + 5, st[sp].n); 372 stpop(st, &sp); 373 mvbuf(&s, &n, &rv, nb); 374 continue; 375 } 376 } 377 378 /* set to parse the elements */ 379 st[sp].t = T_list_elem; 380 st[sp].v = et; 381 st[sp].n = nv - 1; 382 mvbuf(&s, &n, &rv, 5); 383 break; 384 } 385 386 /* list elem */ 387 case T_list_elem: 388 { 389 uint8_t et = st[sp].v; 390 xprintf("[T_list] elem rv:%d, i:%d\n", rv, st[sp].n); 391 stpop(st, &sp); 392 /* push the element onto stack */ 393 if (stadd(st, &sp, et)) 394 { 395 break; 396 } 397 else 398 { 399 return ESTACK; 400 } 401 } 402 } 403 } 404 405 /* all done */ 406 return rv; 407 }