array_safety.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright 2021 DeepMind Technologies Limited
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef MUJOCO_SAMPLE_ARRAY_SAFETY_H_
  15. #define MUJOCO_SAMPLE_ARRAY_SAFETY_H_
  16. #include <algorithm>
  17. #include <cstdarg>
  18. #include <cstddef>
  19. #include <cstdio>
  20. #include <cstring>
  21. // Provides safe alternatives to the sizeof() operator and standard library functions for handling
  22. // null-terminated (C-style) strings in raw char arrays.
  23. //
  24. // These functions make use of compile-time array sizes to limit read and write operations to within
  25. // the array bounds. They are designed to trigger a compile error if the array size cannot be
  26. // determined at compile time (e.g. when an array has decayed into a pointer).
  27. //
  28. // They do not perform runtime bound checks.
  29. namespace mujoco {
  30. namespace sample_util {
  31. // returns sizeof(arr)
  32. // use instead of sizeof() to avoid unintended array-to-pointer decay
  33. template <typename T, int N>
  34. static constexpr std::size_t sizeof_arr(const T(&arr)[N]) {
  35. return sizeof(arr);
  36. }
  37. // like std::strcmp but it will not read beyond the bound of either lhs or rhs
  38. template <std::size_t N1, std::size_t N2>
  39. static inline int strcmp_arr(const char (&lhs)[N1], const char (&rhs)[N2]) {
  40. return std::strncmp(lhs, rhs, std::min(N1, N2));
  41. }
  42. // like std::strlen but it will not read beyond the bound of str
  43. // if str is not null-terminated, returns sizeof(str)
  44. template <std::size_t N>
  45. static inline std::size_t strlen_arr(const char (&str)[N]) {
  46. for (std::size_t i = 0; i < N; ++i) {
  47. if (str[i] == '\0') {
  48. return i;
  49. }
  50. }
  51. return N;
  52. }
  53. // like std::sprintf but will not write beyond the bound of dest
  54. // dest is guaranteed to be null-terminated
  55. template <std::size_t N>
  56. static inline int sprintf_arr(char (&dest)[N], const char* format, ...) {
  57. std::va_list vargs;
  58. va_start(vargs, format);
  59. int retval = std::vsnprintf(dest, N, format, vargs);
  60. va_end(vargs);
  61. return retval;
  62. }
  63. // like std::strcat but will not write beyond the bound of dest
  64. // dest is guaranteed to be null-terminated
  65. template <std::size_t N>
  66. static inline char* strcat_arr(char (&dest)[N], const char* src) {
  67. const std::size_t dest_len = strlen_arr(dest);
  68. const std::size_t dest_size = sizeof_arr(dest);
  69. for (std::size_t i = dest_len; i < dest_size; ++i) {
  70. dest[i] = src[i - dest_len];
  71. if (!dest[i]) {
  72. break;
  73. }
  74. }
  75. dest[dest_size - 1] = '\0';
  76. return dest;
  77. }
  78. // like std::strcpy but won't write beyond the bound of dest
  79. // dest is guaranteed to be null-terminated
  80. template <std::size_t N>
  81. static inline char* strcpy_arr(char (&dest)[N], const char* src) {
  82. {
  83. std::size_t i = 0;
  84. for (; src[i] && i < N - 1; ++i) {
  85. dest[i] = src[i];
  86. }
  87. dest[i] = '\0';
  88. }
  89. return &dest[0];
  90. }
  91. } // namespace sample_util
  92. } // namespace mujoco
  93. #endif // MUJOCO_SAMPLE_ARRAY_SAFETY_H_