1 /* Copyright (C) 2007-2010 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 13 /* 14 * Contains implementation of memory checking framework in the emulator. 15 */ 16 17 #include "qemu-queue.h" 18 #include "qemu_file.h" 19 #include "elff_api.h" 20 #include "memcheck.h" 21 #include "memcheck_proc_management.h" 22 #include "memcheck_util.h" 23 #include "memcheck_logging.h" 24 25 // ============================================================================= 26 // Global data 27 // ============================================================================= 28 29 /* Controls what messages from the guest should be printed to emulator's 30 * stdout. This variable holds a combinations of TRACE_LIBC_XXX flags. */ 31 uint32_t trace_flags = 0; 32 33 /* Global flag, indicating whether or not memchecking has been enabled 34 * for the current emulator session. 1 means that memchecking has been enabled, 35 * 0 means that memchecking has not been enabled. */ 36 int memcheck_enabled = 0; 37 38 /* Global flag, indicating whether or not __ld/__stx_mmu should be instrumented 39 * for checking for access violations. If read / write access violation check 40 * has been disabled by -memcheck flags, there is no need to instrument mmu 41 * routines and waste performance. 42 * 1 means that instrumenting is required, 0 means that instrumenting is not 43 * required. */ 44 int memcheck_instrument_mmu = 0; 45 46 /* Global flag, indicating whether or not memchecker is collecting call stack. 47 * 1 - call stack is being collected, 0 means that stack is not being 48 * collected. */ 49 int memcheck_watch_call_stack = 1; 50 51 // ============================================================================= 52 // Static routines. 53 // ============================================================================= 54 55 /* Prints invalid pointer access violation information. 56 * Param: 57 * proc - Process that caused access violation. 58 * ptr - Pointer that caused access violation. 59 * routine - If 1, access violation has occurred in 'free' routine. 60 * If 2, access violation has occurred in 'realloc' routine. 61 */ 62 static void 63 av_invalid_pointer(ProcDesc* proc, target_ulong ptr, int routine) 64 { 65 if (trace_flags & TRACE_CHECK_INVALID_PTR_ENABLED) { 66 printf("memcheck: Access violation is detected in process %s[pid=%u]:\n" 67 " INVALID POINTER 0x%08X is used in '%s' operation.\n" 68 " Allocation descriptor for this pointer has not been found in the\n" 69 " allocation map for the process. Most likely, this is an attempt\n" 70 " to %s a pointer that has been freed.\n", 71 proc->image_path, proc->pid, ptr, routine == 1 ? "free" : "realloc", 72 routine == 1 ? "free" : "reallocate"); 73 } 74 } 75 76 /* Prints read / write access violation information. 77 * Param: 78 * proc - Process that caused access violation. 79 * desc - Allocation descriptor for the violation. 80 * addr - Address at which vilation has occurred. 81 * data_size - Size of data accessed at the 'addr'. 82 * val - If access violation has occurred at write operation, this parameter 83 * contains value that's being written to 'addr'. For read violation this 84 * parameter is not used. 85 * retaddr - Code address (in TB) where access violation has occurred. 86 * is_read - If 1, access violation has occurred when memory at 'addr' has been 87 * read. If 0, access violation has occurred when memory was written. 88 */ 89 static void 90 av_access_violation(ProcDesc* proc, 91 MallocDescEx* desc, 92 target_ulong addr, 93 uint32_t data_size, 94 uint64_t val, 95 target_ulong retaddr, 96 int is_read) 97 { 98 target_ulong vaddr; 99 Elf_AddressInfo elff_info; 100 ELFF_HANDLE elff_handle = NULL; 101 102 desc->malloc_desc.av_count++; 103 if ((is_read && !(trace_flags & TRACE_CHECK_READ_VIOLATION_ENABLED)) || 104 (!is_read && !(trace_flags & TRACE_CHECK_WRITE_VIOLATION_ENABLED))) { 105 return; 106 } 107 108 /* Convert host address to guest address. */ 109 vaddr = memcheck_tpc_to_gpc(retaddr); 110 printf("memcheck: Access violation is detected in process %s[pid=%u]:\n", 111 proc->image_path, proc->pid); 112 113 /* Obtain routine, filename / line info for the address. */ 114 const MMRangeDesc* rdesc = procdesc_get_range_desc(proc, vaddr); 115 if (rdesc != NULL) { 116 int elff_res; 117 printf(" In module %s at address 0x%08X\n", rdesc->path, vaddr); 118 elff_res = 119 memcheck_get_address_info(vaddr, rdesc, &elff_info, &elff_handle); 120 if (elff_res == 0) { 121 printf(" In routine %s in %s/%s:%u\n", 122 elff_info.routine_name, elff_info.dir_name, 123 elff_info.file_name, elff_info.line_number); 124 if (elff_info.inline_stack != NULL) { 125 const Elf_InlineInfo* inl = elff_info.inline_stack; 126 int index = 0; 127 for (; inl[index].routine_name != NULL; index++) { 128 char align[64]; 129 size_t set_align = 4 + index * 2; 130 if (set_align >= sizeof(align)) { 131 set_align = sizeof(align) -1; 132 } 133 memset(align, ' ', set_align); 134 align[set_align] = '\0'; 135 printf("%s", align); 136 if (inl[index].inlined_in_file == NULL) { 137 printf("inlined to %s in unknown location\n", 138 inl[index].routine_name); 139 } else { 140 printf("inlined to %s in %s/%s:%u\n", 141 inl[index].routine_name, 142 inl[index].inlined_in_file_dir, 143 inl[index].inlined_in_file, 144 inl[index].inlined_at_line); 145 } 146 } 147 } 148 elff_free_pc_address_info(elff_handle, &elff_info); 149 elff_close(elff_handle); 150 } else if (elff_res == 1) { 151 printf(" Unable to obtain routine information. Symbols file is not found.\n"); 152 } else { 153 printf(" Unable to obtain routine information.\n" 154 " Symbols file doesn't contain debugging information for address 0x%08X.\n", 155 mmrangedesc_get_module_offset(rdesc, vaddr)); 156 } 157 } else { 158 printf(" In unknown module at address 0x%08X\n", vaddr); 159 } 160 161 printf(" Process attempts to %s %u bytes %s address 0x%08X\n", 162 is_read ? "read" : "write", data_size, 163 is_read ? "from" : "to", addr); 164 printf(" Accessed range belongs to the %s guarding area of allocated block.\n", 165 addr < (target_ulong)mallocdesc_get_user_ptr(&desc->malloc_desc) ? 166 "prefix" : "suffix"); 167 printf(" Allocation descriptor for this violation:\n"); 168 memcheck_dump_malloc_desc(desc, 1, 0); 169 } 170 171 /* Validates access to a guest address. 172 * Param: 173 * addr - Virtual address in the guest space where memory is accessed. 174 * data_size - Size of the accessed data. 175 * proc_ptr - Upon exit from this routine contains pointer to the process 176 * descriptor for the current process, or NULL, if no such descriptor has 177 * been found. 178 * desc_ptr - Upon exit from this routine contains pointer to the allocation 179 * descriptor matching given address range, or NULL, if allocation 180 * descriptor for the validated memory range has not been found. 181 * Return: 182 * 0 if access to the given guest address range doesn't violate anything, or 183 * 1 if given guest address range doesn't match any entry in the current 184 * process allocation descriptors map, or 185 * -1 if a violation has been detected. 186 */ 187 static int 188 memcheck_common_access_validation(target_ulong addr, 189 uint32_t data_size, 190 ProcDesc** proc_ptr, 191 MallocDescEx** desc_ptr) 192 { 193 MallocDescEx* desc; 194 target_ulong validating_range_end; 195 target_ulong user_range_end; 196 197 ProcDesc* proc = get_current_process(); 198 *proc_ptr = proc; 199 if (proc == NULL) { 200 *desc_ptr = NULL; 201 return 1; 202 } 203 204 desc = procdesc_find_malloc_for_range(proc, addr, data_size); 205 *desc_ptr = desc; 206 if (desc == NULL) { 207 return 1; 208 } 209 210 /* Verify that validating address range doesn't start before the address 211 * available to the user. */ 212 if (addr < mallocdesc_get_user_ptr(&desc->malloc_desc)) { 213 // Stepped on the prefix guarding area. 214 return -1; 215 } 216 217 validating_range_end = addr + data_size; 218 user_range_end = mallocdesc_get_user_alloc_end(&desc->malloc_desc); 219 220 /* Verify that validating address range ends inside the user block. 221 * We may step on the suffix guarding area because of alignment issue. 222 * For example, the application code reads last byte in the allocated block 223 * with something like this: 224 * 225 * char last_byte_value = *(char*)last_byte_address; 226 * 227 * and this code got compiled into something like this: 228 * 229 * mov eax, [last_byte_address]; 230 * mov [last_byte_value], al; 231 * 232 * In this case we will catch a read from the suffix area, even though 233 * there were no errors in the code. So, in order to prevent such "false 234 * negative" alarms, lets "forgive" this violation. 235 * There is one bad thing about this "forgivness" though, as it may very 236 * well be, that in real life some of these "out of bound" bytes will cross 237 * page boundaries, marching into a page that has not been mapped to the 238 * process. 239 */ 240 if (validating_range_end <= user_range_end) { 241 // Validating address range is fully contained inside the user block. 242 return 0; 243 } 244 245 /* Lets see if this AV is caused by an alignment issue.*/ 246 if ((validating_range_end - user_range_end) < data_size) { 247 /* Could be an alignment. */ 248 return 0; 249 } 250 251 return -1; 252 } 253 254 /* Checks if process has allocation descriptors for pages defined by a buffer. 255 * Param: 256 * addr - Starting address of a buffer. 257 * buf_size - Buffer size. 258 * Return: 259 * 1 if process has allocations descriptors for pages defined by a buffer, or 260 * 0 if pages containing given buffer don't have any memory allocations in 261 * them. 262 */ 263 static inline int 264 procdesc_contains_allocs(ProcDesc* proc, target_ulong addr, uint32_t buf_size) { 265 if (proc != NULL) { 266 // Beginning of the page containing last byte in range. 267 const target_ulong end_page = (addr + buf_size - 1) & TARGET_PAGE_MASK; 268 // Adjust beginning of the range to the beginning of the page. 269 addr &= TARGET_PAGE_MASK; 270 // Total size of range to check for descriptors. 271 buf_size = end_page - addr + TARGET_PAGE_SIZE + 1; 272 return procdesc_find_malloc_for_range(proc, addr, buf_size) ? 1 : 0; 273 } else { 274 return 0; 275 } 276 } 277 278 // ============================================================================= 279 // Memchecker API. 280 // ============================================================================= 281 282 void 283 memcheck_init(const char* tracing_flags) 284 { 285 if (*tracing_flags == '0') { 286 // Memchecker is disabled. 287 return; 288 } else if (*tracing_flags == '1') { 289 // Set default tracing. 290 trace_flags = TRACE_CHECK_LEAK_ENABLED | 291 TRACE_CHECK_READ_VIOLATION_ENABLED | 292 TRACE_CHECK_INVALID_PTR_ENABLED | 293 TRACE_CHECK_WRITE_VIOLATION_ENABLED; 294 } 295 296 // Parse -memcheck option params, converting them into tracing flags. 297 while (*tracing_flags) { 298 switch (*tracing_flags) { 299 case 'A': 300 // Enable all emulator's tracing messages. 301 trace_flags |= TRACE_ALL_ENABLED; 302 break; 303 case 'F': 304 // Enable fork() tracing. 305 trace_flags |= TRACE_PROC_FORK_ENABLED; 306 break; 307 case 'S': 308 // Enable guest process staring tracing. 309 trace_flags |= TRACE_PROC_START_ENABLED; 310 break; 311 case 'E': 312 // Enable guest process exiting tracing. 313 trace_flags |= TRACE_PROC_EXIT_ENABLED; 314 break; 315 case 'C': 316 // Enable clone() tracing. 317 trace_flags |= TRACE_PROC_CLONE_ENABLED; 318 break; 319 case 'N': 320 // Enable new PID allocation tracing. 321 trace_flags |= TRACE_PROC_NEW_PID_ENABLED; 322 break; 323 case 'B': 324 // Enable libc.so initialization tracing. 325 trace_flags |= TRACE_PROC_LIBC_INIT_ENABLED; 326 break; 327 case 'L': 328 // Enable memory leaks tracing. 329 trace_flags |= TRACE_CHECK_LEAK_ENABLED; 330 break; 331 case 'I': 332 // Enable invalid free / realloc pointer tracing. 333 trace_flags |= TRACE_CHECK_INVALID_PTR_ENABLED; 334 break; 335 case 'R': 336 // Enable reading violations tracing. 337 trace_flags |= TRACE_CHECK_READ_VIOLATION_ENABLED; 338 break; 339 case 'W': 340 // Enable writing violations tracing. 341 trace_flags |= TRACE_CHECK_WRITE_VIOLATION_ENABLED; 342 break; 343 case 'M': 344 // Enable module mapping tracing. 345 trace_flags |= TRACE_PROC_MMAP_ENABLED; 346 break; 347 default: 348 break; 349 } 350 if (trace_flags == TRACE_ALL_ENABLED) { 351 break; 352 } 353 tracing_flags++; 354 } 355 356 /* Lets see if we need to instrument MMU, injecting memory access checking. 357 * We instrument MMU only if we monitor read, or write memory access. */ 358 if (trace_flags & (TRACE_CHECK_READ_VIOLATION_ENABLED | 359 TRACE_CHECK_WRITE_VIOLATION_ENABLED)) { 360 memcheck_instrument_mmu = 1; 361 } else { 362 memcheck_instrument_mmu = 0; 363 } 364 365 memcheck_init_proc_management(); 366 367 /* Lets check env. variables needed for memory checking. */ 368 if (getenv("ANDROID_PROJECT_OUT") == NULL) { 369 printf("memcheck: Missing ANDROID_PROJECT_OUT environment variable, that is used\n" 370 "to calculate path to symbol files.\n"); 371 } 372 373 // Always set this flag at the very end of the initialization! 374 memcheck_enabled = 1; 375 } 376 377 void 378 memcheck_guest_libc_initialized(uint32_t pid) 379 { 380 ProcDesc* proc = get_process_from_pid(pid); 381 if (proc == NULL) { 382 ME("memcheck: Unable to obtain process for libc_init pid=%u", pid); 383 return; 384 } 385 proc->flags |= PROC_FLAG_LIBC_INITIALIZED; 386 387 /* When process initializes its own libc.so instance, it means that now 388 * it has fresh heap. So, at this point we must get rid of all entries 389 * (inherited and transition) that were collected in this process' 390 * allocation descriptors map. */ 391 procdesc_empty_alloc_map(proc); 392 T(PROC_LIBC_INIT, "memcheck: libc.so has been initialized for %s[pid=%u]\n", 393 proc->image_path, proc->pid); 394 } 395 396 void 397 memcheck_guest_alloc(target_ulong guest_address) 398 { 399 MallocDescEx desc; 400 MallocDescEx replaced; 401 RBTMapResult insert_res; 402 ProcDesc* proc; 403 ThreadDesc* thread; 404 uint32_t indx; 405 406 // Copy allocation descriptor from guest to emulator. 407 memcheck_get_malloc_descriptor(&desc.malloc_desc, guest_address); 408 desc.flags = 0; 409 desc.call_stack = NULL; 410 desc.call_stack_count = 0; 411 412 proc = get_process_from_pid(desc.malloc_desc.allocator_pid); 413 if (proc == NULL) { 414 ME("memcheck: Unable to obtain process for allocation pid=%u", 415 desc.malloc_desc.allocator_pid); 416 memcheck_fail_alloc(guest_address); 417 return; 418 } 419 420 if (!procdesc_is_executing(proc)) { 421 desc.flags |= MDESC_FLAG_TRANSITION_ENTRY; 422 } 423 424 /* Copy thread's calling stack to the allocation descriptor. */ 425 thread = get_current_thread(); 426 desc.call_stack_count = thread->call_stack_count; 427 if (desc.call_stack_count) { 428 desc.call_stack = qemu_malloc(desc.call_stack_count * sizeof(target_ulong)); 429 if (desc.call_stack == NULL) { 430 ME("memcheck: Unable to allocate %u bytes for the calling stack", 431 desc.call_stack_count * sizeof(target_ulong)); 432 return; 433 } 434 } 435 436 /* Thread's calling stack is in descending order (i.e. first entry in the 437 * thread's stack is the most distant routine from the current one). On the 438 * other hand, we keep calling stack entries in allocation descriptor in 439 * assending order. */ 440 for (indx = 0; indx < thread->call_stack_count; indx++) { 441 desc.call_stack[indx] = 442 thread->call_stack[thread->call_stack_count - 1 - indx].call_address; 443 } 444 445 // Save malloc descriptor in the map. 446 insert_res = procdesc_add_malloc(proc, &desc, &replaced); 447 if (insert_res == RBT_MAP_RESULT_ENTRY_INSERTED) { 448 // Invalidate TLB cache for the allocated block. 449 if (memcheck_instrument_mmu) { 450 invalidate_tlb_cache(desc.malloc_desc.ptr, 451 mallocdesc_get_alloc_end(&desc.malloc_desc)); 452 } 453 } else if (insert_res == RBT_MAP_RESULT_ENTRY_REPLACED) { 454 /* We don't expect to have another entry in the map that matches 455 * inserting entry. This is an error condition for us, indicating 456 * that we somehow lost track of memory allocations. */ 457 ME("memcheck: Duplicate allocation blocks:"); 458 if (VERBOSE_CHECK(memcheck)) { 459 printf(" New block:\n"); 460 memcheck_dump_malloc_desc(&desc, 1, 1); 461 printf(" Replaced block:\n"); 462 memcheck_dump_malloc_desc(&replaced, 1, 1); 463 } 464 if (replaced.call_stack != NULL) { 465 qemu_free(replaced.call_stack); 466 } 467 } else { 468 ME("memcheck: Unable to insert an entry to the allocation map:"); 469 if (VERBOSE_CHECK(memcheck)) { 470 memcheck_dump_malloc_desc(&desc, 1, 1); 471 } 472 memcheck_fail_alloc(guest_address); 473 return; 474 } 475 } 476 477 void 478 memcheck_guest_free(target_ulong guest_address) 479 { 480 MallocFree desc; 481 MallocDescEx pulled; 482 int pull_res; 483 ProcDesc* proc; 484 485 // Copy free descriptor from guest to emulator. 486 memcheck_get_free_descriptor(&desc, guest_address); 487 488 proc = get_process_from_pid(desc.free_pid); 489 if (proc == NULL) { 490 ME("memcheck: Unable to obtain process for pid=%u on free", 491 desc.free_pid); 492 memcheck_fail_free(guest_address); 493 return; 494 } 495 496 // Pull matching entry from the map. 497 pull_res = procdesc_pull_malloc(proc, desc.ptr, &pulled); 498 if (pull_res) { 499 av_invalid_pointer(proc, desc.ptr, 1); 500 memcheck_fail_free(guest_address); 501 return; 502 } 503 504 // Make sure that ptr has expected value 505 if (desc.ptr != mallocdesc_get_user_ptr(&pulled.malloc_desc)) { 506 if (trace_flags & TRACE_CHECK_INVALID_PTR_ENABLED) { 507 printf("memcheck: Access violation is detected in process %s[pid=%u]:\n", 508 proc->image_path, proc->pid); 509 printf(" INVALID POINTER 0x%08X is used in 'free' operation.\n" 510 " This pointer is unexpected for 'free' operation, as allocation\n" 511 " descriptor found for this pointer in the process' allocation map\n" 512 " suggests that 0x%08X is the pointer to be used to free this block.\n" 513 " Allocation descriptor matching the pointer:\n", 514 desc.ptr, 515 (uint32_t)mallocdesc_get_user_ptr(&pulled.malloc_desc)); 516 memcheck_dump_malloc_desc(&pulled, 1, 0); 517 } 518 } 519 if (pulled.call_stack != NULL) { 520 qemu_free(pulled.call_stack); 521 } 522 } 523 524 void 525 memcheck_guest_query_malloc(target_ulong guest_address) 526 { 527 MallocDescQuery qdesc; 528 MallocDescEx* found; 529 ProcDesc* proc; 530 531 // Copy free descriptor from guest to emulator. 532 memcheck_get_query_descriptor(&qdesc, guest_address); 533 534 proc = get_process_from_pid(qdesc.query_pid); 535 if (proc == NULL) { 536 ME("memcheck: Unable to obtain process for pid=%u on query_%s", 537 qdesc.query_pid, qdesc.routine == 1 ? "free" : "realloc"); 538 memcheck_fail_query(guest_address); 539 return; 540 } 541 542 // Find allocation entry for the given address. 543 found = procdesc_find_malloc(proc, qdesc.ptr); 544 if (found == NULL) { 545 av_invalid_pointer(proc, qdesc.ptr, qdesc.routine); 546 memcheck_fail_query(guest_address); 547 return; 548 } 549 550 // Copy allocation descriptor back to the guest's space. 551 memcheck_set_malloc_descriptor(qdesc.desc, &found->malloc_desc); 552 } 553 554 void 555 memcheck_guest_print_str(target_ulong str) { 556 char str_copy[4096]; 557 memcheck_get_guest_string(str_copy, str, sizeof(str_copy)); 558 printf("%s", str_copy); 559 } 560 561 /* Validates read operations, detected in __ldx_mmu routine. 562 * This routine is called from __ldx_mmu wrapper implemented in 563 * softmmu_template.h on condition that loading is occurring from user memory. 564 * Param: 565 * addr - Virtual address in the guest space where memory is read. 566 * data_size - Size of the read. 567 * retaddr - Code address (in TB) that accesses memory. 568 * Return: 569 * 1 if TLB record for the accessed page should be invalidated in order to 570 * ensure that subsequent attempts to access data in this page will cause 571 * __ld/stx_mmu to be used. If memchecker is no longer interested in monitoring 572 * access to this page, this routine returns 0. 573 */ 574 int 575 memcheck_validate_ld(target_ulong addr, 576 uint32_t data_size, 577 target_ulong retaddr) 578 { 579 ProcDesc* proc; 580 MallocDescEx* desc; 581 582 int res = memcheck_common_access_validation(addr, data_size, &proc, &desc); 583 if (res == -1) { 584 av_access_violation(proc, desc, addr, data_size, 0, retaddr, 1); 585 return 1; 586 } 587 588 /* Even though descriptor for the given address range has not been found, 589 * we need to make sure that pages containing the given address range 590 * don't contain other descriptors. */ 591 return res ? procdesc_contains_allocs(proc, addr, data_size) : 0; 592 } 593 594 /* Validates write operations, detected in __stx_mmu routine. 595 * This routine is called from __stx_mmu wrapper implemented in 596 * softmmu_template.h on condition that storing is occurring from user memory. 597 * Param: 598 * addr - Virtual address in the guest space where memory is written. 599 * data_size - Size of the write. 600 * value - Value to be written. Note that we typecast all values to 64 bits, 601 * since this will fit all data sizes. 602 * retaddr - Code address (in TB) that accesses memory. 603 * Return: 604 * 1 if TLB record for the accessed page should be invalidated in order to 605 * ensure that subsequent attempts to access data in this page will cause 606 * __ld/stx_mmu to be used. If memchecker is no longer interested in monitoring 607 * access to this page, this routine returns 0. 608 */ 609 int 610 memcheck_validate_st(target_ulong addr, 611 uint32_t data_size, 612 uint64_t value, 613 target_ulong retaddr) 614 { 615 MallocDescEx* desc; 616 ProcDesc* proc; 617 618 int res = memcheck_common_access_validation(addr, data_size, &proc, &desc); 619 if (res == -1) { 620 av_access_violation(proc, desc, addr, data_size, value, retaddr, 0); 621 return 1; 622 } 623 624 /* Even though descriptor for the given address range has not been found, 625 * we need to make sure that pages containing the given address range 626 * don't contain other descriptors. */ 627 return res ? procdesc_contains_allocs(proc, addr, data_size) : 0; 628 } 629 630 /* Checks if given address range in the context of the current process is under 631 * surveillance. 632 * Param: 633 * addr - Starting address of a range. 634 * size - Range size. 635 * Return: 636 * boolean: 1 if address range contains memory that require access violation 637 * detection, or 0 if given address range is in no interest to the memchecker. 638 */ 639 int 640 memcheck_is_checked(target_ulong addr, uint32_t size) { 641 return procdesc_contains_allocs(get_current_process(), addr, size) ? 1 : 0; 642 } 643