bh_leb128.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "bh_leb128.h"
  6. bh_leb_read_status_t
  7. bh_leb_read(const uint8 *buf, const uint8 *buf_end, uint32 maxbits, bool sign,
  8. uint64 *p_result, size_t *p_offset)
  9. {
  10. uint64 result = 0;
  11. uint32 shift = 0;
  12. uint32 offset = 0, bcnt = 0;
  13. uint64 byte;
  14. while (true) {
  15. /* uN or SN must not exceed ceil(N/7) bytes */
  16. if (bcnt + 1 > (maxbits + 6) / 7) {
  17. return BH_LEB_READ_TOO_LONG;
  18. }
  19. if ((uintptr_t)buf + offset + 1 < (uintptr_t)buf
  20. || (uintptr_t)buf + offset + 1 > (uintptr_t)buf_end) {
  21. return BH_LEB_READ_UNEXPECTED_END;
  22. }
  23. byte = buf[offset];
  24. offset += 1;
  25. result |= ((byte & 0x7f) << shift);
  26. shift += 7;
  27. bcnt += 1;
  28. if ((byte & 0x80) == 0) {
  29. break;
  30. }
  31. }
  32. if (!sign && maxbits == 32 && shift >= maxbits) {
  33. /* The top bits set represent values > 32 bits */
  34. if (((uint8)byte) & 0xf0)
  35. return BH_LEB_READ_OVERFLOW;
  36. }
  37. else if (sign && maxbits == 32) {
  38. if (shift < maxbits) {
  39. /* Sign extend, second-highest bit is the sign bit */
  40. if ((uint8)byte & 0x40)
  41. result |= (~((uint64)0)) << shift;
  42. }
  43. else {
  44. /* The top bits should be a sign-extension of the sign bit */
  45. bool sign_bit_set = ((uint8)byte) & 0x8;
  46. int top_bits = ((uint8)byte) & 0xf0;
  47. if ((sign_bit_set && top_bits != 0x70)
  48. || (!sign_bit_set && top_bits != 0))
  49. return BH_LEB_READ_OVERFLOW;
  50. }
  51. }
  52. else if (sign && maxbits == 64) {
  53. if (shift < maxbits) {
  54. /* Sign extend, second-highest bit is the sign bit */
  55. if ((uint8)byte & 0x40)
  56. result |= (~((uint64)0)) << shift;
  57. }
  58. else {
  59. /* The top bits should be a sign-extension of the sign bit */
  60. bool sign_bit_set = ((uint8)byte) & 0x1;
  61. int top_bits = ((uint8)byte) & 0xfe;
  62. if ((sign_bit_set && top_bits != 0x7e)
  63. || (!sign_bit_set && top_bits != 0))
  64. return BH_LEB_READ_OVERFLOW;
  65. }
  66. }
  67. *p_offset = offset;
  68. *p_result = result;
  69. return BH_LEB_READ_SUCCESS;
  70. }