如何制作(ptr + len)>安全吗? [英] How to make (ptr + len) > lim safe?

查看:72
本文介绍了如何制作(ptr + len)>安全吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢在使用缓冲区

数据时使用限制指针作为哨兵。意思是我用ptr< lim,其中ptr和lim都是指针

而不是n 0来确定是否可以安全地继续写入

位置。理由是它更简单,因此更安全,因为

你不会经常重新计算整数n。


然而,我遇到了一个如果失败了,我想知道专家会做什么。


如果我想预先计算一个指针加上一个长度的话超出限制

指针我有一个很容易失败的情况。有两种可能的

表达式:


1)将长度添加到指针并检查它是否超过

限制如:


char * ptr,* lim;

int len;


if((ptr + len)> = lim)

返回-1;


这不行,因为len可能是如此之大以至于计算指针

值变为负数,表达式的计算结果为false。


2)计算限制和指针之间的可用空间,并比较

长度:


if((lim - ptr)=< len)

返回-1;


这也不行,因为如果lim是(char *) - 1并且ptr相对较小,那么计算出的空间仍然是负数,因此条件是

false。我不确定这是否会在32位平台上发生,但在64位/ b $ b位上它当然可以。


请注意,我也总是要检查确定lim!= NULL并且ptr< lim。


所以给出lim,ptr和len的任何值,除了lim!= NULL和ptr<

lim,你会用什么表达来安全确保ptr + len比

少于lim?

Mike

解决方案

< blockquote> 2008年1月16日星期三23:02:12 -0500,Michael B Allen< io **** @ gmail.com>

在comp.lang.c中写道:


我喜欢在处理缓冲区

数据时使用限制指针作为哨兵。意思是我用ptr< lim,其中ptr和lim都是指针

而不是n 0来确定是否可以安全地继续写入

位置。理由是它更简单,因此更安全,因为

你不会经常重新计算整数n。


然而,我遇到了一个如果失败了,我想知道专家会做什么。


如果我想预先计算一个指针加上一个长度的话超出限制

指针我有一个很容易失败的情况。有两种可能的

表达式:


1)将长度添加到指针并检查它是否超过

限制如:

char * ptr,* lim;

int len;



这里真正的问题是你使用错误的整数类型来支付
len。使用size_t,这是表达对象的自然大小

大小。


即使你必须处理一个有符号的int类型,也要将它分配给一个

size_t。如果signed int值为负,它将转换为

非常大的size_t值。


然后检查size_t值是否为最大值,决定

on。当且仅当size_t值(无符号)在

范围内时,你应该将它应用于指针。


if( (ptr + len)> = lim)

返回-1;


这不行,因为len可能太大而计算指针

值变为负值,表达式的计算结果为false。



指针不是有符号值,它们不是负面的并且

" positive"。


2)计算限制和指针之间的可用空间并比较

到所需的长度:


if((lim - ptr)=< len)

返回-1;


这也不行,因为如果lim是(char *) - 1而ptr相对较小,那么计算空间仍然是负数,因此条件是

假。我不确定这是否会在32位平台上发生,但在64位/ b $ b位上它当然可以。


请注意,我也总是要检查确定lim!= NULL并且ptr< lim。


所以给出lim,ptr和len的任何值,除了lim!= NULL和ptr<

lim,你会用什么表达来安全确保ptr + len比
少于lim?



如上所述,我的第一步是将长度转换为

size_t,一个无符号类型,然后检查预定义的最大值。


-

Jack Klein

主页: http://JK-Technology.Com

常见问题解答

comp.lang.c < a rel =nofollowhref =http://c-faq.com/target =_ blank> http://c-faq.com/

comp。 lang.c ++ http://www.parashift.com/c++-faq- lite /

alt.comp.lang.learn.c-c ++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html


James Kuyper< jameskuy ... @ verizon.netwrote:


Michael B Allen写道:


请注意,我总是检查以确保lim!= NULL

和那个ptr< LIM。



但是,如果ptr和lim都指向同一个数组的结尾或者结束,并且如果ptr< lim,那么lim-ptr必须是b $ b积极的,这是标准所说的。



请参阅章节和诗句。


不是直接的,而是通过对其所说的关于<的推断br />
二进制'' - ''运算符和''<''运算符,当执行

指针时:


6.5 .6p9:当两个指针被减去时,两个指针都必须指向同一个数组对象的元素,或者指向数组对象的最后一个元素的
;结果是两个数组

元素下标的

差异。


6.5.8p5:" ...具有较大

下标值的数组元素的指针比指向具有较低下标值的相同数组的元素的指针大得多。


由于ptr< lim,lim指向一个数组元素,其下标值比一个ptr指向的更大。指针的

差异等于下标的差额

,因此必须是正数。



不要求PTRDIFF_MAX> = SIZE_MAX。那么,



情况下指针添加有效的情况下,(ptr + PTRDIFF_MAX + 1 - ptr)的值是多少?


-

Peter


Michael B Allen< io **** @ gmail.comwrote:

< snip>


1)将长度添加到指针并检查它是否超过

限制,如:


char * ptr,* lim;

int len;


if((ptr + len)> = lim)

return -1;


这不行,因为len可能太大,以至于计算指针

值变为负值且表达式求值为假。



你在哪里获得len?我的场景可能是这样的:


size_t fill(unsigned char * dst,size_t dstlen){

unsigned char * pos = dst;

unsigned char * end = dst + dstlen;


while(pos< end){

*(pos ++)='' 。';;

}


返回pos - dst;

}


指出,如果调用者没有编写错误代码,我可以依赖

指针算法定义良好。如果dstlen太长, (或者,如果我用
使用带符号的整数,为负数),显然调用者正在传递

关于其输出缓冲区的错误信息,而且我无能为力

这样做。


2)计算限制和指针之间的可用空间并比较

到达所需长度:


if((lim - ptr)=< len)

return -1;


这也不行,因为如果lim是(char *) - 1而ptr是相对

小,计算空间仍然是负数,因此条件是

false。我不确定这是否会在32位平台上发生,但在64位/ b $ b位上肯定可以。



负指针没有意义。但是,与上述相关,如果lim计算不正确,那只是一个bug,而且这种类型的使用不会受到限制

。 br />


请注意,我总是检查以确保lim!= NULL并且ptr< LIM。



之前的测试没有必要。重要的是如果lim> = ptr和ptr<

lim(并且该ptr指向有效对象)。测试一个NULL指针是

[希望]是多余的,也是测试错误的

条件的一个例子:重要的不是lim是NULL,而是ptr是否为NULL 。并且在

任何事件中,如果ptr和lim都是NULL,你就可以了,只要

关系成立。


所以给定lim,ptr和len的任何值,除了lim!= NULL和ptr<

lim,你会使用什么表达式来安全地确保ptr + len是

比林少?



以这种方式使用指针的真正问题是,从技术上讲,

如果计算的话,你不能用这种方式做任意指针关节

未定义。在分段架构上,如果len大于实际对象的大小,则通过计算和比较

这样的指针来获得未定义的行为。同样,如果你像我经常那样,在对象结束时超过一个位置增加一个位置

指针。在Unix中,这些操作定义为
_better_(虽然你明显遇到溢出问题)和

通常更宽容,因为它们超出了C的其他要求

规范,例如平面内存模型。但是我已经遇到了调试器

,它们依赖于C规范的字母,而且它变得足够痛苦,我对使用指针更加小心这样。


相反,我越来越有可能使用一个位置指针。这是

只是一个整数计数器,而不是比较指针我比较

计数器与长度参数。 (当然,使用无符号算术。)

这样计数器可以超出长度,例如,如果我想继续计算操作的输出长度,b / b
即使我已经从目标缓冲区空间运行了
。 (Cf snprintf)。这可能会稍微增加CPU工作量,因为我可能需要更频繁地重新计算指针(因为

反对增加指针,这也可以作为计数器) )。或者它

可能没有。


I like to use limit pointers as sentinels when working on buffers
of data. Meaning I use ptr < lim where ptr and lim are both pointers
rather than n 0 to determine if it is safe to proceed writing to that
location. The rationale is that it is simpler and thus safer because
you''re not constantly recomputing integer n.

However, I''ve run into a case where this fails and I''d like to know what
the experts would do.

If I want to precompute if a pointer plus a length will exceed the limit
pointer I have a condition that can easily fail. There are two possible
expressions:

1) Add the length to the pointer and check to see if it exceeds the
limit like:

char *ptr, *lim;
int len;

if ((ptr + len) >= lim)
return -1;

This is not ok because len could be so large that the computed pointer
value becomes negative and the expression evaluates to false.

2) Compute the available space between the limit and pointer and compare
that to the required length:

if ((lim - ptr) =< len)
return -1;

This is also not ok because if lim is (char *)-1 and ptr is relatively
small, the computed space is still negative and thus the condition is
false. I''m not sure if this will happen on 32 bit platforms but on 64
bit it certainly can.

Note that I always also check to make sure lim != NULL and that ptr < lim.

So given any values for lim, ptr and len except lim != NULL and ptr <
lim, what expression would you use to safely ensure that ptr + len is
less than lim?

Mike

解决方案

On Wed, 16 Jan 2008 23:02:12 -0500, Michael B Allen <io****@gmail.com>
wrote in comp.lang.c:

I like to use limit pointers as sentinels when working on buffers
of data. Meaning I use ptr < lim where ptr and lim are both pointers
rather than n 0 to determine if it is safe to proceed writing to that
location. The rationale is that it is simpler and thus safer because
you''re not constantly recomputing integer n.

However, I''ve run into a case where this fails and I''d like to know what
the experts would do.

If I want to precompute if a pointer plus a length will exceed the limit
pointer I have a condition that can easily fail. There are two possible
expressions:

1) Add the length to the pointer and check to see if it exceeds the
limit like:

char *ptr, *lim;
int len;

The real problem here is that you are using the wrong integer type for
len. Use a size_t, which is the natural size for expressing object
sizes.

Even if you have to deal with a signed int type, assign it to a
size_t. If the signed int value is negative, it will convert to a
very large size_t value.

Then check the size_t value against a maximum value, which you decide
on. If and only if the size_t value (which is unsigned) is within
your limits should you apply it to the pointer.

if ((ptr + len) >= lim)
return -1;

This is not ok because len could be so large that the computed pointer
value becomes negative and the expression evaluates to false.

Pointers are not signed values, they don''t come in "negative" and
"positive".

2) Compute the available space between the limit and pointer and compare
that to the required length:

if ((lim - ptr) =< len)
return -1;

This is also not ok because if lim is (char *)-1 and ptr is relatively
small, the computed space is still negative and thus the condition is
false. I''m not sure if this will happen on 32 bit platforms but on 64
bit it certainly can.

Note that I always also check to make sure lim != NULL and that ptr < lim.

So given any values for lim, ptr and len except lim != NULL and ptr <
lim, what expression would you use to safely ensure that ptr + len is
less than lim?

As I said above, my first step would be to convert the length to
size_t, an unsigned type, and check that against a predefined maximum.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html


James Kuyper <jameskuy...@verizon.netwrote:

Michael B Allen wrote:

Note that I always also check to make sure lim != NULL
and that ptr < lim.


However, if ptr and lim both point into or one past the end
of the same array, and if ptr < lim, then lim-ptr has to be
positive, and that is something the standard does say.

Chapter and verse please.

Not directly, but by inference from what it says about the
binary ''-'' operator and the ''<'' operator, when acting on
pointers:

6.5.6p9: "When two pointers are subtracted, both shall
point to elements of the same array object, or one past
the last element of the array object; the result is the
difference of the subscripts of the two array
elements."

6.5.8p5: "... pointers to array elements with larger
subscript values compare greater than pointers to
elements of the same array with lower subscript values."

Since ptr<lim, lim points to an array element with a
larger subscript value than the one ptr points at. The
difference of the pointers is equal to the difference
of the subscripts, and therefore has to be positive.

There is no requirement that PTRDIFF_MAX >= SIZE_MAX. So,
what is the value of (ptr + PTRDIFF_MAX + 1 - ptr) in the
case where the pointer additions are valid?

--
Peter


Michael B Allen <io****@gmail.comwrote:
<snip>

1) Add the length to the pointer and check to see if it exceeds the
limit like:

char *ptr, *lim;
int len;

if ((ptr + len) >= lim)
return -1;

This is not ok because len could be so large that the computed pointer
value becomes negative and the expression evaluates to false.

Where are you getting len? The scenario for me might be something like:

size_t fill(unsigned char *dst, size_t dstlen) {
unsigned char *pos = dst;
unsigned char *end = dst + dstlen;

while (pos < end) {
*(pos++) = ''.'';
}

return pos - dst;
}

Point being, if the caller hasn''t written buggy code I can depend on the
pointer arithmetic being well defined. If dstlen is "too long" (or, if I
were using a signed integerr, negative), clearly the caller is passing
erroneous information about their output buffer, and there''s nothing I can
do about that.

2) Compute the available space between the limit and pointer and compare
that to the required length:

if ((lim - ptr) =< len)
return -1;

This is also not ok because if lim is (char *)-1 and ptr is relatively
small, the computed space is still negative and thus the condition is
false. I''m not sure if this will happen on 32 bit platforms but on 64
bit it certainly can.

A negative pointer doesn''t make sense. But, related to above, if lim was
calculated improperly, that''s simply a bug, and one of a sort not restricted
to this type of usage.

Note that I always also check to make sure lim != NULL and that ptr < lim.

The former test isn''t necessary. All that matters is if lim >= ptr and ptr <
lim (and that ptr points to a valid object). Testing for a NULL pointer is
[hopefully] superfluous and also an example of testing for the wrong
condition: it matters not that lim is NULL, but whether ptr is NULL. And in
any event, if both ptr and lim are NULL you''re okay, as long as the
relationship holds.

So given any values for lim, ptr and len except lim != NULL and ptr <
lim, what expression would you use to safely ensure that ptr + len is
less than lim?

The real problem with using pointers this way is that, technically speaking,
you cannot do arbitrary pointer arthmetic this way if the calculations would
be undefined. On a segmented architecture if len is greater than the size of
the actual object, you get undefined behavior by computing and comparing
such a pointer. Likewise if you, as I often did, incremented a positional
pointer past [one past] the end of the object. In Unix these operations are
_better_ defined (though you obviously run into issues with overflow) and
usually more forgiving, because they make other requirements beyond the C
specification, such as a flat memory model. But I have run into debuggers
which have depended on the letter of the C specification, and it became
enough of a pain that I''m more careful about using pointers this way.

Instead, I''m increasingly more likely to use a position "pointer" which is
simply an integer counter, and instead of comparing pointers I compare the
counter with a length paramater. (Using unsigned arithmetic, of course.)
This way the counter can extend beyond the length, for instance if I want to
continuing calculating the output length of an operation, even if I''ve run
out of destination buffer space. (Cf snprintf). This may end up in slightly
additional CPU work, because I may need to recompute pointers more often (as
opposed to incrementing a pointer, which can also act as the counter). Or it
may not.


这篇关于如何制作(ptr + len)&gt;安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆