|
22 | 22 |
|
23 | 23 | #include "tysan/tysan.h" |
24 | 24 |
|
| 25 | +#include <stdint.h> |
25 | 26 | #include <string.h> |
26 | 27 |
|
27 | 28 | using namespace __sanitizer; |
@@ -254,10 +255,68 @@ static void reportError(void *Addr, int Size, tysan_type_descriptor *TD, |
254 | 255 | } |
255 | 256 | } |
256 | 257 |
|
| 258 | +ALWAYS_INLINE |
| 259 | +static void SetShadowType(tysan_type_descriptor *td, |
| 260 | + tysan_type_descriptor **shadowData, |
| 261 | + uint64_t AccessSize) { |
| 262 | + *shadowData = td; |
| 263 | + uint64_t shadowDataInt = (uint64_t)shadowData; |
| 264 | + |
| 265 | + for (uint64_t i = 1; i < AccessSize; ++i) { |
| 266 | + int64_t dataOffset = i << PtrShift(); |
| 267 | + int64_t *badShadowData = (int64_t *)(shadowDataInt + dataOffset); |
| 268 | + int64_t badTD = int64_t(i) * -1; |
| 269 | + *badShadowData = badTD; |
| 270 | + } |
| 271 | +} |
| 272 | + |
| 273 | +ALWAYS_INLINE |
| 274 | +static bool GetNotAllBadTD(uint64_t ShadowDataInt, uint64_t AccessSize) { |
| 275 | + bool notAllBadTD = false; |
| 276 | + for (uint64_t i = 1; i < AccessSize; ++i) { |
| 277 | + int64_t **unkShadowData = (int64_t **)(ShadowDataInt + (i << PtrShift())); |
| 278 | + int64_t *ILdTD = *unkShadowData; |
| 279 | + notAllBadTD = notAllBadTD || (ILdTD != nullptr); |
| 280 | + } |
| 281 | + return notAllBadTD; |
| 282 | +} |
| 283 | + |
| 284 | +ALWAYS_INLINE |
| 285 | +static bool GetNotAllUnkTD(uint64_t ShadowDataInt, uint64_t AccessSize) { |
| 286 | + bool notAllBadTD = false; |
| 287 | + for (uint64_t i = 1; i < AccessSize; ++i) { |
| 288 | + int64_t *badShadowData = (int64_t *)(ShadowDataInt + (i << PtrShift())); |
| 289 | + int64_t ILdTD = *badShadowData; |
| 290 | + notAllBadTD = notAllBadTD || (ILdTD >= 0); |
| 291 | + } |
| 292 | + return notAllBadTD; |
| 293 | +} |
| 294 | + |
257 | 295 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
258 | | -__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { |
259 | | - GET_CALLER_PC_BP_SP; |
| 296 | +__tysan_instrument_mem_inst(char *dest, char *src, uint64_t size, |
| 297 | + bool needsMemMove) { |
| 298 | + tysan_type_descriptor **destShadowDataPtr = shadow_for(dest); |
| 299 | + |
| 300 | + if (!src) { |
| 301 | + internal_memset((char *)destShadowDataPtr, 0, size << PtrShift()); |
| 302 | + return; |
| 303 | + } |
| 304 | + |
| 305 | + uint64_t srcInt = (uint64_t)src; |
| 306 | + uint64_t srcShadowInt = ((srcInt & AppMask()) << PtrShift()) + ShadowAddr(); |
| 307 | + uint64_t *srcShadow = (uint64_t *)srcShadowInt; |
260 | 308 |
|
| 309 | + if (needsMemMove) { |
| 310 | + internal_memmove((char *)destShadowDataPtr, srcShadow, size << PtrShift()); |
| 311 | + } else { |
| 312 | + internal_memcpy((char *)destShadowDataPtr, srcShadow, size << PtrShift()); |
| 313 | + } |
| 314 | +} |
| 315 | + |
| 316 | +ALWAYS_INLINE |
| 317 | +static void __tysan_check_internal(void *addr, int size, |
| 318 | + tysan_type_descriptor *td, int flags, |
| 319 | + uptr pc, uptr bp, uptr sp) { |
261 | 320 | bool IsRead = flags & 1; |
262 | 321 | bool IsWrite = flags & 2; |
263 | 322 | const char *AccessStr; |
@@ -300,6 +359,64 @@ __tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { |
300 | 359 | } |
301 | 360 | } |
302 | 361 |
|
| 362 | +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
| 363 | +__tysan_check(void *addr, int size, tysan_type_descriptor *td, int flags) { |
| 364 | + GET_CALLER_PC_BP_SP; |
| 365 | + __tysan_check_internal(addr, size, td, flags, pc, bp, sp); |
| 366 | +} |
| 367 | + |
| 368 | +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
| 369 | +__tysan_instrument_with_shadow_update(void *ptr, tysan_type_descriptor *td, |
| 370 | + bool sanitizeFunction, |
| 371 | + uint64_t accessSize, int flags) { |
| 372 | + tysan_type_descriptor **shadowData = shadow_for(ptr); |
| 373 | + tysan_type_descriptor *loadedTD = *shadowData; |
| 374 | + bool shadowIsNull = loadedTD == nullptr; |
| 375 | + |
| 376 | + // TODO, sanitizeFunction is known at compile time, so maybe this is split |
| 377 | + // into two different functions |
| 378 | + if (sanitizeFunction) { |
| 379 | + |
| 380 | + if (td != loadedTD) { |
| 381 | + |
| 382 | + // We now know that the types did not match (we're on the slow path). If |
| 383 | + // the type is unknown, then set it. |
| 384 | + if (shadowIsNull) { |
| 385 | + // We're about to set the type. Make sure that all bytes in the value |
| 386 | + // are also of unknown type. |
| 387 | + bool isAllUnknownTD = GetNotAllUnkTD((uint64_t)shadowData, accessSize); |
| 388 | + if (isAllUnknownTD) { |
| 389 | + GET_CALLER_PC_BP_SP; |
| 390 | + __tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp); |
| 391 | + } |
| 392 | + SetShadowType(td, shadowData, accessSize); |
| 393 | + } else { |
| 394 | + GET_CALLER_PC_BP_SP; |
| 395 | + __tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp); |
| 396 | + } |
| 397 | + } else { |
| 398 | + // We appear to have the right type. Make sure that all other bytes in |
| 399 | + // the type are still marked as interior bytes. If not, call the runtime. |
| 400 | + bool isNotAllBadTD = GetNotAllBadTD((uint64_t)shadowData, accessSize); |
| 401 | + if (isNotAllBadTD) { |
| 402 | + GET_CALLER_PC_BP_SP; |
| 403 | + __tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp); |
| 404 | + } |
| 405 | + } |
| 406 | + } else if (shadowIsNull) { |
| 407 | + SetShadowType(td, shadowData, accessSize); |
| 408 | + } |
| 409 | +} |
| 410 | + |
| 411 | +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void |
| 412 | +__tysan_set_shadow_type(void *ptr, tysan_type_descriptor *td, |
| 413 | + uint64_t accessSize) { |
| 414 | + // In the mode where writes always set the type, for a write (which does |
| 415 | + // not also read), we just set the type. |
| 416 | + tysan_type_descriptor **shadow = shadow_for(ptr); |
| 417 | + SetShadowType(td, shadow, accessSize); |
| 418 | +} |
| 419 | + |
303 | 420 | Flags __tysan::flags_data; |
304 | 421 |
|
305 | 422 | SANITIZER_INTERFACE_ATTRIBUTE uptr __tysan_shadow_memory_address; |
|
0 commit comments