Issue |
131502
|
Summary |
[compiler-rt] BlocksRuntime `_Block_dump` function doesn't dump current ABI
|
Labels |
new issue
|
Assignees |
|
Reporter |
ADKaster
|
The helper method here:
https://github.com/llvm/llvm-project/blob/508db53d1af5b01f8f8275229f087bb6407f0033/compiler-rt/lib/BlocksRuntime/runtime.c#L620-684
Prints that the compiler is "obsolete" on current clang.
The following test program prints the following with both Apple clang version 16.0.0 (clang-1600.0.26.6) and
Homebrew clang version 19.1.7:
```
Block compiled by obsolete compiler, please recompile source for this Block
closure flags: 0x42000000
^0x16bbcf3c0 (new layout) =
isa: stack Block
flags: HASHELP
refcount: 0
invoke: 0x104233cb8
descriptor: 0x104234058
descriptor->reserved: 0
descriptor->size: 40
descriptor->copy helper: 0x104233ce8
descriptor->dispose helper: 0x104233d20
x=1
```
<details>
<summary>Program source, with most contents copied from BlocksRuntime/runtime.c</summary>
```c++
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
enum {
BLOCK_REFCOUNT_MASK = (0xffff),
BLOCK_NEEDS_FREE = (1 << 24),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_DESCRIPTOR = (1 << 29)
};
extern "C" void * _NSConcreteStackBlock[32];
extern "C" void * _NSConcreteMallocBlock[32];
extern "C" void * _NSConcreteAutoBlock[32];
extern "C" void * _NSConcreteFinalizingBlock[32];
extern "C" void * _NSConcreteGlobalBlock[32];
extern "C" void * _NSConcreteWeakBlockVariable[32];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
const char *_Block_dump(const void *block);
const char *_Block_dump(const void *block) {
struct Block_layout const*closure = (struct Block_layout const*)block;
static char buffer[512];
char *cp = buffer;
if (closure == NULL) {
sprintf(cp, "NULL passed to _Block_dump\n");
return buffer;
}
if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
printf("closure flags: 0x%08x\n", closure->flags);
//exit(1);
}
cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
if (closure->isa == NULL) {
cp += sprintf(cp, "isa: NULL\n");
}
else if (closure->isa == _NSConcreteStackBlock) {
cp += sprintf(cp, "isa: stack Block\n");
}
else if (closure->isa == _NSConcreteMallocBlock) {
cp += sprintf(cp, "isa: malloc heap Block\n");
}
else if (closure->isa == _NSConcreteAutoBlock) {
cp += sprintf(cp, "isa: GC heap Block\n");
}
else if (closure->isa == _NSConcreteGlobalBlock) {
cp += sprintf(cp, "isa: global Block\n");
}
else if (closure->isa == _NSConcreteFinalizingBlock) {
cp += sprintf(cp, "isa: finalizing Block\n");
}
else {
cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
}
cp += sprintf(cp, "flags:");
if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
cp += sprintf(cp, " HASDESCRIPTOR");
}
if (closure->flags & BLOCK_NEEDS_FREE) {
cp += sprintf(cp, " FREEME");
}
if (closure->flags & BLOCK_IS_GC) {
cp += sprintf(cp, " ISGC");
}
if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
cp += sprintf(cp, " HASHELP");
}
if (closure->flags & BLOCK_HAS_CTOR) {
cp += sprintf(cp, " HASCTOR");
}
cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
{
struct Block_descriptor *dp = closure->descriptor;
cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
}
}
return buffer;
}
#pragma clang diagnostic pop
int main()
{
__block int x = 0;
auto b = ^{
x++;
};
printf("%s", _Block_dump(b));
b();
printf("x=%d\n", x);
}
```
</details>
As for *why* I want an accurate dump method, I'm trying to add support to my own std::function-like type erased function for blocks.
I actually want to inspect the pointed-to Block_layout so that I can scan the captured variables for GC pointers in my naive mark-and-sweep conservative GC. And it doesn't seem like I've got a full grasp on which bytes to look for GC pointers in based on my manual debugging.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs