从c中的指针窃取两位

时间:2014-04-01 18:09:17

标签: c pointers bit-manipulation

我试图从地址窃取两个LSB位,我写了 以下内联函数。我想确认一下是否有效 64位和32位机器。

我使用stealing bits from a pointer帖作为参考。

我得到一个奇怪的错误,其中getAddress()返回0x100

0x1没问题,因为setFlag1(NULL)会返回此地址

0x2没问题,因为setFlag2(NULL)会返回此地址

0x11也可以setFlag1(NULL)setFlag2(NULL)将返回此地址

但我不确定哪种组合会返回0x100

#define UINTPTR_MAX_XOR_WITH_1 (uintptr_t) (UINTPTR_MAX ^ 0x1)
#define UINTPTR_MAX_XOR_WITH_2 (uintptr_t) (UINTPTR_MAX ^ 0x2)
#define UINTPTR_MAX_XOR_WITH_3 (uintptr_t) (UINTPTR_MAX ^ 0x3)

struct node
{
    unsigned long key;
    struct node* lChild;    //format <address,flag2,flag1>
    struct node* rChild;    //format <address,flag2,flag1>
};

static inline struct node* getAddress(struct node* p)
{
    return (struct node*)((uintptr_t) p & UINTPTR_MAX_XOR_WITH_3);
}

static inline bool isFlag2(struct node* p)
{
    return (uintptr_t) p & 0x2;
}

static inline bool isFlag1(struct node* p)
{
    return (uintptr_t) p & 0x1;
}

static inline struct node* setFlag1(struct node* p)
{
    return((struct node*) (((uintptr_t) p & UINTPTR_MAX_XOR_WITH_1) | 0x1));
}

static inline struct node* unsetFlag1(struct node* p)
{
    return((struct node*) (((uintptr_t) p & UINTPTR_MAX_XOR_WITH_1)));
}

static inline struct node* setFlag2(struct node* p)
{
    return((struct node*) (((uintptr_t) p & UINTPTR_MAX_XOR_WITH_2) | 0x2));
}

2 个答案:

答案 0 :(得分:3)

该bug可能与此标记方案无关。

getAddress可以返回地址0x100:您只需将其输入0x1000x103

你的getAddress函数所做的就是删除两个最低有效位以恢复对齐的指针。由于0x100在两个最低有效位中是明确的,getAddress正在完成其工作。

GIGO:垃圾进,垃圾出来!

添加一些跟踪以打印进入getAddress的值。

当取消引用空指针以获取结构成员的地址时,有时会产生类似0x100的地址:null_pointer->something_at_offset_256。当然,一般来说,它们可以以多种方式出现。

答案 1 :(得分:2)

各种函数依赖于UINTPTR_MAX设置了2个LSBits。重新编码以消除这种依赖性。

一些简化。

执行bool返回的比较。

确保这些函数在被调用时被正确声明或原型化。否则,返回值假定为int并且可以解释0x100返回。

问题可能仍在其他地方。你是否期望像setFlag1(p)这样的调用设置p的位(哪些代码不能执行)或者返回一个设置了位的指针(代码是什么)?

static inline struct node* getAddress(struct node* p) {
  return (struct node*)((uintptr_t) p & ~((uintptr_t) 3));
}

static inline bool isFlag1(struct node* p) {
  return ((uintptr_t) p & 1) != 0;
}

static inline bool isFlag2(struct node* p) {
  return ((uintptr_t) p & 2) != 0;
}

static inline struct node* setFlag1(struct node* p) {
  return (struct node*) ((uintptr_t) p | 1);
}

static inline struct node* unsetFlag1(struct node* p) {
  return (struct node*) ((uintptr_t) p & ~((uintptr_t) 1));
}

static inline struct node* setFlag2(struct node* p)
  return (struct node*) ((uintptr_t) p | 2);
}

static inline struct node* unsetFlag2(struct node* p) {
  return (struct node*) ((uintptr_t) p & ~((uintptr_t) 2));
}

[编辑] 在审核中,可以确定UINTPTR_MAX 2 LSBits必须为1.请参阅上面的@Kaz评论。