errors.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. package msgp
  2. import (
  3. "reflect"
  4. "strconv"
  5. )
  6. const resumableDefault = false
  7. var (
  8. // ErrShortBytes is returned when the
  9. // slice being decoded is too short to
  10. // contain the contents of the message
  11. ErrShortBytes error = errShort{}
  12. // ErrRecursion is returned when the maximum recursion limit is reached for an operation.
  13. // This should only realistically be seen on adversarial data trying to exhaust the stack.
  14. ErrRecursion error = errRecursion{}
  15. // ErrLimitExceeded is returned when a set limit is exceeded.
  16. // Limits can be set on the Reader to prevent excessive memory usage by adversarial data.
  17. ErrLimitExceeded error = errLimitExceeded{}
  18. // this error is only returned
  19. // if we reach code that should
  20. // be unreachable
  21. fatal error = errFatal{}
  22. )
  23. // Error is the interface satisfied
  24. // by all of the errors that originate
  25. // from this package.
  26. type Error interface {
  27. error
  28. // Resumable returns whether
  29. // or not the error means that
  30. // the stream of data is malformed
  31. // and the information is unrecoverable.
  32. Resumable() bool
  33. }
  34. // contextError allows msgp Error instances to be enhanced with additional
  35. // context about their origin.
  36. type contextError interface {
  37. Error
  38. // withContext must not modify the error instance - it must clone and
  39. // return a new error with the context added.
  40. withContext(ctx string) error
  41. }
  42. // Cause returns the underlying cause of an error that has been wrapped
  43. // with additional context.
  44. func Cause(e error) error {
  45. out := e
  46. if e, ok := e.(errWrapped); ok && e.cause != nil {
  47. out = e.cause
  48. }
  49. return out
  50. }
  51. // Resumable returns whether or not the error means that the stream of data is
  52. // malformed and the information is unrecoverable.
  53. func Resumable(e error) bool {
  54. if e, ok := e.(Error); ok {
  55. return e.Resumable()
  56. }
  57. return resumableDefault
  58. }
  59. // WrapError wraps an error with additional context that allows the part of the
  60. // serialized type that caused the problem to be identified. Underlying errors
  61. // can be retrieved using Cause()
  62. //
  63. // The input error is not modified - a new error should be returned.
  64. //
  65. // ErrShortBytes is not wrapped with any context due to backward compatibility
  66. // issues with the public API.
  67. func WrapError(err error, ctx ...any) error {
  68. switch e := err.(type) {
  69. case errShort:
  70. return e
  71. case contextError:
  72. return e.withContext(ctxString(ctx))
  73. default:
  74. return errWrapped{cause: err, ctx: ctxString(ctx)}
  75. }
  76. }
  77. func addCtx(ctx, add string) string {
  78. if ctx != "" {
  79. return add + "/" + ctx
  80. } else {
  81. return add
  82. }
  83. }
  84. // errWrapped allows arbitrary errors passed to WrapError to be enhanced with
  85. // context and unwrapped with Cause()
  86. type errWrapped struct {
  87. cause error
  88. ctx string
  89. }
  90. func (e errWrapped) Error() string {
  91. if e.ctx != "" {
  92. return e.cause.Error() + " at " + e.ctx
  93. } else {
  94. return e.cause.Error()
  95. }
  96. }
  97. func (e errWrapped) Resumable() bool {
  98. if e, ok := e.cause.(Error); ok {
  99. return e.Resumable()
  100. }
  101. return resumableDefault
  102. }
  103. // Unwrap returns the cause.
  104. func (e errWrapped) Unwrap() error { return e.cause }
  105. type errShort struct{}
  106. func (e errShort) Error() string { return "msgp: too few bytes left to read object" }
  107. func (e errShort) Resumable() bool { return false }
  108. type errFatal struct {
  109. ctx string
  110. }
  111. func (f errFatal) Error() string {
  112. out := "msgp: fatal decoding error (unreachable code)"
  113. if f.ctx != "" {
  114. out += " at " + f.ctx
  115. }
  116. return out
  117. }
  118. func (f errFatal) Resumable() bool { return false }
  119. func (f errFatal) withContext(ctx string) error { f.ctx = addCtx(f.ctx, ctx); return f }
  120. type errRecursion struct{}
  121. func (e errRecursion) Error() string { return "msgp: recursion limit reached" }
  122. func (e errRecursion) Resumable() bool { return false }
  123. type errLimitExceeded struct{}
  124. func (e errLimitExceeded) Error() string { return "msgp: configured reader limit exceeded" }
  125. func (e errLimitExceeded) Resumable() bool { return false }
  126. // ArrayError is an error returned
  127. // when decoding a fix-sized array
  128. // of the wrong size
  129. type ArrayError struct {
  130. Wanted uint32
  131. Got uint32
  132. ctx string
  133. }
  134. // Error implements the error interface
  135. func (a ArrayError) Error() string {
  136. out := "msgp: wanted array of size " + strconv.Itoa(int(a.Wanted)) + "; got " + strconv.Itoa(int(a.Got))
  137. if a.ctx != "" {
  138. out += " at " + a.ctx
  139. }
  140. return out
  141. }
  142. // Resumable is always 'true' for ArrayErrors
  143. func (a ArrayError) Resumable() bool { return true }
  144. func (a ArrayError) withContext(ctx string) error { a.ctx = addCtx(a.ctx, ctx); return a }
  145. // IntOverflow is returned when a call
  146. // would downcast an integer to a type
  147. // with too few bits to hold its value.
  148. type IntOverflow struct {
  149. Value int64 // the value of the integer
  150. FailedBitsize int // the bit size that the int64 could not fit into
  151. ctx string
  152. }
  153. // Error implements the error interface
  154. func (i IntOverflow) Error() string {
  155. str := "msgp: " + strconv.FormatInt(i.Value, 10) + " overflows int" + strconv.Itoa(i.FailedBitsize)
  156. if i.ctx != "" {
  157. str += " at " + i.ctx
  158. }
  159. return str
  160. }
  161. // Resumable is always 'true' for overflows
  162. func (i IntOverflow) Resumable() bool { return true }
  163. func (i IntOverflow) withContext(ctx string) error { i.ctx = addCtx(i.ctx, ctx); return i }
  164. // UintOverflow is returned when a call
  165. // would downcast an unsigned integer to a type
  166. // with too few bits to hold its value
  167. type UintOverflow struct {
  168. Value uint64 // value of the uint
  169. FailedBitsize int // the bit size that couldn't fit the value
  170. ctx string
  171. }
  172. // Error implements the error interface
  173. func (u UintOverflow) Error() string {
  174. str := "msgp: " + strconv.FormatUint(u.Value, 10) + " overflows uint" + strconv.Itoa(u.FailedBitsize)
  175. if u.ctx != "" {
  176. str += " at " + u.ctx
  177. }
  178. return str
  179. }
  180. // Resumable is always 'true' for overflows
  181. func (u UintOverflow) Resumable() bool { return true }
  182. func (u UintOverflow) withContext(ctx string) error { u.ctx = addCtx(u.ctx, ctx); return u }
  183. // InvalidTimestamp is returned when an invalid timestamp is encountered
  184. type InvalidTimestamp struct {
  185. Nanos int64 // value of the nano, if invalid
  186. FieldLength int // Unexpected field length.
  187. ctx string
  188. }
  189. // Error implements the error interface
  190. func (u InvalidTimestamp) Error() (str string) {
  191. if u.Nanos > 0 {
  192. str = "msgp: timestamp nanosecond field value " + strconv.FormatInt(u.Nanos, 10) + " exceeds maximum allows of 999999999"
  193. } else if u.FieldLength >= 0 {
  194. str = "msgp: invalid timestamp field length " + strconv.FormatInt(int64(u.FieldLength), 10) + " - must be 4, 8 or 12"
  195. }
  196. if u.ctx != "" {
  197. str += " at " + u.ctx
  198. }
  199. return str
  200. }
  201. // Resumable is always 'true' for overflows
  202. func (u InvalidTimestamp) Resumable() bool { return true }
  203. func (u InvalidTimestamp) withContext(ctx string) error { u.ctx = addCtx(u.ctx, ctx); return u }
  204. // UintBelowZero is returned when a call
  205. // would cast a signed integer below zero
  206. // to an unsigned integer.
  207. type UintBelowZero struct {
  208. Value int64 // value of the incoming int
  209. ctx string
  210. }
  211. // Error implements the error interface
  212. func (u UintBelowZero) Error() string {
  213. str := "msgp: attempted to cast int " + strconv.FormatInt(u.Value, 10) + " to unsigned"
  214. if u.ctx != "" {
  215. str += " at " + u.ctx
  216. }
  217. return str
  218. }
  219. // Resumable is always 'true' for overflows
  220. func (u UintBelowZero) Resumable() bool { return true }
  221. func (u UintBelowZero) withContext(ctx string) error {
  222. u.ctx = ctx
  223. return u
  224. }
  225. // A TypeError is returned when a particular
  226. // decoding method is unsuitable for decoding
  227. // a particular MessagePack value.
  228. type TypeError struct {
  229. Method Type // Type expected by method
  230. Encoded Type // Type actually encoded
  231. ctx string
  232. }
  233. // Error implements the error interface
  234. func (t TypeError) Error() string {
  235. out := "msgp: attempted to decode type " + quoteStr(t.Encoded.String()) + " with method for " + quoteStr(t.Method.String())
  236. if t.ctx != "" {
  237. out += " at " + t.ctx
  238. }
  239. return out
  240. }
  241. // Resumable returns 'true' for TypeErrors
  242. func (t TypeError) Resumable() bool { return true }
  243. func (t TypeError) withContext(ctx string) error { t.ctx = addCtx(t.ctx, ctx); return t }
  244. // returns either InvalidPrefixError or
  245. // TypeError depending on whether or not
  246. // the prefix is recognized
  247. func badPrefix(want Type, lead byte) error {
  248. t := getType(lead)
  249. if t == InvalidType {
  250. return InvalidPrefixError(lead)
  251. }
  252. return TypeError{Method: want, Encoded: t}
  253. }
  254. // InvalidPrefixError is returned when a bad encoding
  255. // uses a prefix that is not recognized in the MessagePack standard.
  256. // This kind of error is unrecoverable.
  257. type InvalidPrefixError byte
  258. // Error implements the error interface
  259. func (i InvalidPrefixError) Error() string {
  260. return "msgp: unrecognized type prefix 0x" + strconv.FormatInt(int64(i), 16)
  261. }
  262. // Resumable returns 'false' for InvalidPrefixErrors
  263. func (i InvalidPrefixError) Resumable() bool { return false }
  264. // ErrUnsupportedType is returned
  265. // when a bad argument is supplied
  266. // to a function that takes `interface{}`.
  267. type ErrUnsupportedType struct {
  268. T reflect.Type
  269. ctx string
  270. }
  271. // Error implements error
  272. func (e *ErrUnsupportedType) Error() string {
  273. out := "msgp: type " + quoteStr(e.T.String()) + " not supported"
  274. if e.ctx != "" {
  275. out += " at " + e.ctx
  276. }
  277. return out
  278. }
  279. // Resumable returns 'true' for ErrUnsupportedType
  280. func (e *ErrUnsupportedType) Resumable() bool { return true }
  281. func (e *ErrUnsupportedType) withContext(ctx string) error {
  282. o := *e
  283. o.ctx = addCtx(o.ctx, ctx)
  284. return &o
  285. }
  286. // simpleQuoteStr is a simplified version of strconv.Quote for TinyGo,
  287. // which takes up a lot less code space by escaping all non-ASCII
  288. // (UTF-8) bytes with \x. Saves about 4k of code size
  289. // (unicode tables, needed for IsPrint(), are big).
  290. // It lives in errors.go just so we can test it in errors_test.go
  291. func simpleQuoteStr(s string) string {
  292. const (
  293. lowerhex = "0123456789abcdef"
  294. )
  295. sb := make([]byte, 0, len(s)+2)
  296. sb = append(sb, `"`...)
  297. l: // loop through string bytes (not UTF-8 characters)
  298. for i := 0; i < len(s); i++ {
  299. b := s[i]
  300. // specific escape chars
  301. switch b {
  302. case '\\':
  303. sb = append(sb, `\\`...)
  304. case '"':
  305. sb = append(sb, `\"`...)
  306. case '\a':
  307. sb = append(sb, `\a`...)
  308. case '\b':
  309. sb = append(sb, `\b`...)
  310. case '\f':
  311. sb = append(sb, `\f`...)
  312. case '\n':
  313. sb = append(sb, `\n`...)
  314. case '\r':
  315. sb = append(sb, `\r`...)
  316. case '\t':
  317. sb = append(sb, `\t`...)
  318. case '\v':
  319. sb = append(sb, `\v`...)
  320. default:
  321. // no escaping needed (printable ASCII)
  322. if b >= 0x20 && b <= 0x7E {
  323. sb = append(sb, b)
  324. continue l
  325. }
  326. // anything else is \x
  327. sb = append(sb, `\x`...)
  328. sb = append(sb, lowerhex[b>>4])
  329. sb = append(sb, lowerhex[b&0xF])
  330. continue l
  331. }
  332. }
  333. sb = append(sb, `"`...)
  334. return string(sb)
  335. }