C “strtol”的实现是什么?

C “strtol”的实现是什么?,c,C,我只是好奇而已strtol不要求您指定要处理的字节数,因此理论上,它可能会被输入一个包含要使用的无限数字序列的字符串,从而导致拒绝服务攻击。当然,它很容易被挫败,因为它意识到long的精度已经耗尽(实际上不可能超过一个二进制数的65个字符),没有必要再进一步读取了 但是,strtol还需要根据需要丢弃尽可能多的空白字符,直到遇到第一个非空白字符为止。所以,即使它在读取数字方面很聪明,它也不能被无休止的空白字符串攻击吗 没有单一的strtol实现。我怀疑任何实现都会受到您描述的那种攻击;显而易见的

我只是好奇而已
strtol
不要求您指定要处理的字节数,因此理论上,它可能会被输入一个包含要使用的无限数字序列的字符串,从而导致拒绝服务攻击。当然,它很容易被挫败,因为它意识到long的精度已经耗尽(实际上不可能超过一个二进制数的65个字符),没有必要再进一步读取了


但是,
strtol
还需要根据需要丢弃尽可能多的空白字符,直到遇到第一个非空白字符为止。所以,即使它在读取数字方面很聪明,它也不能被无休止的空白字符串攻击吗

没有单一的
strtol
实现。我怀疑任何实现都会受到您描述的那种攻击;显而易见的实现是只遍历数字序列,而不同时存储所有数字。(请注意,由于前导
0
s,数字序列可以任意长。)


如果您想查看实现的代码,可以下载glibc版本<代码> STRTROR()/<代码> <代码> STDLIB/Struto.C.<代码>

< P>。如果你想看Strutl,你可以在加利福尼亚大学

看到它。
/* 
 * strtol.c --
 *
 *  Source code for the "strtol" library procedure.
 *
 * Copyright (c) 1988 The Regents of the University of California.
 * All rights reserved.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */
static const char rcsid[] = "$Header$ SPRITE (Berkeley)";

#include <ctype.h>

extern unsigned long int strtoul(char *string, char **endPtr, int base);

/*
 *----------------------------------------------------------------------
 *
 * strtol --
 *
 *  Convert an ASCII string into an integer.
 *
 * Results:
 *  The return value is the integer equivalent of string.  If endPtr
 *  is non-NULL, then *endPtr is filled in with the character
 *  after the last one that was part of the integer.  If string
 *  doesn't contain a valid integer value, then zero is returned
 *  and *endPtr is set to string.
 *
 * Side effects:
 *  None.
 *
 *----------------------------------------------------------------------
 */

long int
strtol(
    char *string,       /* String of ASCII digits, possibly
                 * preceded by white space.  For bases
                 * greater than 10, either lower- or
                 * upper-case digits may be used.
                 */
    char **endPtr,      /* Where to store address of terminating
                 * character, or NULL. */
    int base            /* Base for conversion.  Must be less
                 * than 37.  If 0, then the base is chosen
                 * from the leading characters of string:
                 * "0x" means hex, "0" means octal, anything
                 * else means decimal.
                 */
)
{
    register char *p;
    int result;

    /*
     * Skip any leading blanks.
     */
    p = string;
    while (isspace(*p)) {
    p += 1;
    }

    /*
     * Check for a sign.
     */
    if (*p == '-') {
    p += 1;
    result = -1*(strtoul(p, endPtr, base));
    } else {
    if (*p == '+') {
        p += 1;
    }
    result = strtoul(p, endPtr, base);
    }
    if ((result == 0) && (endPtr != 0) && (*endPtr == p)) {
    *endPtr = string;
    }
    return result;
}
/*
*strtol.c--
*
*“strtol”库过程的源代码。
*
* Copyright(C)1988加利福尼亚大学的摄政王。
*版权所有。
*
*特此授予许可,无需书面同意,也无需
*使用、复制、修改和分发本文件的许可费或版税
*任何目的的软件及其文档,前提是
*上述版权声明及以下两段内容见
*此软件的所有副本。
* 
*加利福尼亚大学概不应对任何一方负责。
*因以下原因引起的直接、间接、特殊、附带或后果性损害:
*使用该软件及其文档,即使大学
*加利福尼亚州已被告知可能发生这种损害。
*
*加利福尼亚大学特别否认任何保证,
*包括但不限于对适销性的默示保证
*以及适合特定用途。以下提供的软件是
*“按原样”,加利福尼亚大学没有义务
*提供维护、支持、更新、增强或修改。
*/
静态常量字符rcsid[]=“$Header$SPRITE(Berkeley)”;
#包括
外部无符号长整数字符串(字符*字符串,字符**endPtr,整数基);
/*
*----------------------------------------------------------------------
*
*斯特托--
*
*将ASCII字符串转换为整数。
*
*结果:
*返回值是与字符串等效的整数。如果endPtr
*为非NULL,则*endPtr用字符填充
*最后一个是整数的一部分。如果字符串
*不包含有效的整数值,则返回零
*并且*endPtr设置为string。
*
*副作用:
*没有。
*
*----------------------------------------------------------------------
*/
长整型
斯特托(
字符*字符串,/*ASCII数字字符串,可能
*前面有空格。用于基数
*大于10,低于或低于
*可以使用大写数字。
*/
字符**endPtr,/*在何处存储终止地址
*字符,或NULL*/
用于转换的int base/*base。必须小于
*小于37。如果为0,则选择基数
*从字符串的前导字符:
*“0x”表示十六进制,“0”表示八进制,任何形式
*否则表示十进制。
*/
)
{
寄存器char*p;
int结果;
/*
*跳过任何前导空格。
*/
p=字符串;
while(isspace(*p)){
p+=1;
}
/*
*检查是否有迹象。
*/
如果(*p=='-'){
p+=1;
结果=-1*(strtoul(p,endPtr,base));
}否则{
如果(*p=='+')){
p+=1;
}
结果=strtoul(p,endPtr,base);
}
如果((结果==0)&&(endPtr!=0)&&(*endPtr==p)){
*endPtr=字符串;
}
返回结果;
}
但是,strtol还需要根据需要丢弃尽可能多的空白字符,直到遇到第一个非空白字符为止。所以,即使它在读取数字方面很聪明,它也不能被无休止的空白字符串攻击吗

由于
strtol
对内存中已经存在的字符串起作用,因此在将其输入strtol之前,您必须存储(并从攻击者处读取)一个“无止境”的空白(或忘记NUL终止您的字符串)

由于实现可以计算有效字符串中可能存在的最大位数,因此它不必像您所怀疑的那样继续运行


DoS攻击可能会发生在错误的实现中,但是请检查相关的情况(这是在java和PHP中读取双倍的,但是同样的情况也可能发生在C++或C++实现中)。p> 我的个人实现。我没有使用任何前瞻功能(访问

p[1]
或类似的功能),因此理论上可以将其转换为从流读取的内容(例如
get_long()
调用
getc()
字符)

#包括
#定义LONG_MAX((长)(~0UL>>1))
#定义长_最小值(~LONG_最大值)
intIsSpace(intC);/*36) {
#ifdef EINVAL/*POSIX定义的错误值*/
errno=EINVAL;
#恩迪夫
返回0升;
}
endp=nptr;
while(isspace(*p))
p++;
如果(*p=='+')){
p++;
}else if(*p=='-'){
is_neg=1,p++;
}
如果(*p==“0”){
p++;
/*对于strtol(“0xZ”&endptr,16),endptr应指向“x”;
*指向“”或“0”是不兼容的。
#include <errno.h>
#define LONG_MAX ((long)(~0UL>>1))
#define LONG_MIN (~LONG_MAX)
int isspace(int c); /* <-- Forward declare from <ctype.h> */ 

long strtol(const char *restrict nptr, char **restrict endptr, int base) {
    const char *p = nptr, *endp;
    _Bool is_neg = 0, overflow = 0;
    /* Need unsigned so (-LONG_MIN) can fit in these: */
    unsigned long n = 0UL, cutoff;
    int cutlim;
    if (base < 0 || base == 1 || base > 36) {
#ifdef EINVAL /* errno value defined by POSIX */
        errno = EINVAL;
#endif
        return 0L;
    }
    endp = nptr;
    while (isspace(*p))
        p++;
    if (*p == '+') {
        p++;
    } else if (*p == '-') {
        is_neg = 1, p++;
    }
    if (*p == '0') {
        p++;
        /* For strtol(" 0xZ", &endptr, 16), endptr should point to 'x';
         * pointing to ' ' or '0' is non-compliant.
         * (Many implementations do this wrong.) */
        endp = p;
        if (base == 16 && (*p == 'X' || *p == 'x')) {
            p++;
        } else if (base == 0) {
            if (*p == 'X' || *p == 'x') {
                base = 16, p++;
            } else {
                base = 8;
            }
        }
    } else if (base == 0) {
        base = 10;
    }
    cutoff = (is_neg) ? -(LONG_MIN / base) : LONG_MAX / base;
    cutlim = (is_neg) ? -(LONG_MIN % base) : LONG_MAX % base;
    while (1) {
        int c;
        if (*p >= 'A')
            digit = ((*p - 'A') & (~('a' ^ 'A'))) + 10;
        else if (*p <= '9')
            digit = *p - '0';
        else
            break;
        if (c < 0 || c >= base) break;
        endp = ++p;
        if (overflow) {
            /* endptr should go forward and point to the non-digit character
             * (of the given base); required by ANSI standard. */
            if (endptr) continue;
            break;
        }
        if (n > cutoff || (n == cutoff && c > cutlim)) {
            overflow = 1; continue;
        }
        n = n * base + c;
    }
    if (endptr) *endptr = (char *)endp;
    if (overflow) {
        errno = ERANGE; return ((is_neg) ? LONG_MIN : LONG_MAX);
    }
    return (long)((is_neg) ? -n : n);
}