의 경우에는 정수 오버플로는 무엇입의 결과(unsigned int)*(int)?unsigned int 또는?

StackOverflow https://stackoverflow.com/questions/721861

  •  05-09-2019
  •  | 
  •  

문제

의 경우에는 정수 오버플로는 무엇입의 결과 (unsigned int) * (int) ? unsignedint?어떤 종류는 배열 색인 사용자(operator[] 가)한 char*: int, unsigned int 또는 다른 뭔가?

나는 감사는 다음과 같은 기능,그리고 갑자기 이 질문에 일어났다.기능는 취약점을 줄 17.

// Create a character array and initialize it with init[] 
// repeatedly. The size of this character array is specified by 
// w*h.
char *function4(unsigned int w, unsigned int h, char *init)
{
    char *buf;
    int i;

    if (w*h > 4096)
        return (NULL);

    buf = (char *)malloc(4096+1);
    if (!buf)
        return (NULL);

    for (i=0; i<h; i++)
        memcpy(&buf[i*w], init, w);  // line 17

    buf[4096] = '\0';

    return buf;
}

모두 고려 wh 은 매우 큰 부호 정수입니다.곱하기 라인에서 9 수 있는 기회를 통과하는 유효성 검사를 수행합니다.

지금 문제는에서 선 17.곱하기 int iunsigned int w:는 경우 결과 int, 는 제품입니다 부정적인 결과에 액세스하는 위치가기 buf.는 경우 결과 unsigned int, 에,제품은 항상 긍정적인 결과에 액세스하는 위치 후 buf.

그의 코드 작성을 정당화한다: int 은 너무 큽니다.사람은 아이디어에 이?

이 있는 문서의 형식을 지정합니까?나는 검색을 위해 그것은,하지만 지금까지 아무것도 발견하지 않았.

나는 가정으로 취약성에 관한 한,지 (unsigned int) * (int) 생산 unsigned intint 지 않기 때문에,문제에 컴파일된 개체는 파일,그들은 그냥 바이트입니다.다음 코드와 동일 상관없이 제품의 유형:

unsigned int x = 10;
int y = -10;

printf("%d\n", x * y);  // print x * y in signed integer
printf("%u\n", x * y);  // print x * y in unsigned integer

따라서,그것은 중요하지 않습니다 어떤 종류의 곱셈 반환합니다.그것은 문제는지 소비자 기능이 걸립 intunsigned.

여기에 질문 얼마나 나쁜 기능 또는 개선하는 방법 기능을 더 나은 만들 수 있습니다.이 기능이 있는 취약점입니다.질문에 대해 정확한 행동 기능의에 따라 규정된 행위에서 기준입니다.

도움이 되었습니까?

해결책

질문에 답하기 위해 : int를 곱한 표현식 유형과 서명되지 않은 int는 c/c ++에서 서명되지 않은 int가됩니다.

묵시적 질문에 답하기 위해 정수 산술에서 가능한 오버플로를 처리하는 한 가지 괜찮은 방법은IntSafe"Microsoft의 루틴 세트 :

http://blogs.msdn.com/michael_howard/archive/2006/02/02/523392.aspx

SDK에서 사용할 수 있으며 인라인 구현이 포함되어 있으므로 다른 플랫폼에있는 경우 수행하는 작업을 연구 할 수 있습니다.

다른 팁

W*h 계산을 장거리로, max_uint보다 더 큰지 확인하십시오.

편집 : 대안 : 오버플로 된 경우 (w*h)/h! = w (이것은 항상 그렇습니까?! 맞아야합니까?)

w와 h를 제한하여 w * h가 넘치지 않도록하십시오.

유형 w*i 귀하의 경우 서명되지 않았습니다. 표준을 올바르게 읽으면 규칙은 피연산자가 더 큰 유형 (서명 함)으로 변환되거나 서명 된 유형 ( unsigned int 귀하의 경우).

그러나 서명되지 않더라도 랩 어라운드를 방지하지는 않습니다 (이전에 메모리에 쓰기 buf), 그것이 경우 (i386 플랫폼에서) 될 수 있기 때문에 p[-1] 와 같다 p[-1u]. 어쨌든, 당신의 경우 둘 다 buf[-1] 그리고 buf[big unsigned number] 정의되지 않은 행동이므로 서명/서명되지 않은 질문은 그다지 중요하지 않습니다.

다른 상황에서 서명/부호없는 문제 (예 : (int)(x*y/2) 유형에 따라 다른 결과를 제공합니다 x 그리고 y, 정의되지 않은 행동이없는 경우에도.

9 행에서 오버플로를 확인하여 문제를 해결할 것입니다. 4096은 상당히 작은 상수이며 4096*4096은 대부분의 아키텍처에서 오버플로되지 않기 때문에 (확인해야 함).

if (w>4096 || h>4096 || w*h > 4096)
     return (NULL);

이것은 사건을 제외합니다 w 또는 h 0이면 필요한 경우 확인할 수 있습니다.

일반적으로 다음과 같은 오버플로를 확인할 수 있습니다.

if(w*h > 4096 || (w*h)/w!=h || (w*h)%w!=0)

C/C ++에서 p[n] 표기법은 실제로 쓰기의 바로 가기입니다 *(p+n), 및이 포인터 산술은 부호를 고려합니다. 그래서 p[-1] 유효하며 직전에 값을 나타냅니다 *p.

따라서 정수를 가진 산술 연산자의 결과는 표준에 의해 정의 된 일련의 규칙을 따릅니다.이를 정수 프로모션이라고합니다.

이 페이지를 확인하십시오. int02-c. 정수 변환 규칙을 이해하십시오

2 개의 변경 사항은 더 안전합니다.

if (w >= 4096 || h >= 4096 || w*h > 4096)  return NULL;

...

unsigned i;

또한 버퍼 끝에 글을 쓰거나 읽는 것은 나쁜 생각이 아닙니다. 따라서 질문은 내가 아닌지가 아닙니다w는 음수가 될 수 있지만 0 <= IH +W <= 4096 보유.

따라서 중요한 유형이 아니라 H*i의 결과입니다. 예를 들어, (서명되지 않은) 0x80000000 또는 (int) 0x80000000인지 여부는 차이가 없습니다.

C의 경우 수학 연산자의 오페라가 어떻게 처리되는지에 대한 자세한 내용은 "일반적인 산술 변환"(C99 : 섹션 6.3.1.8, ANSI C K & R A6.5)을 참조하십시오.

예에서 다음 규칙이 적용됩니다.

C99 :

그렇지 않으면, 서명 된 정수 유형이있는 피연산자 유형이 서명되지 않은 정수 유형을 갖는 피연산자 유형의 모든 값을 나타낼 수 있다면, 서명되지 않은 정수 유형을 갖는 피연산자는 서명 된 정수 유형이있는 피연산자 유형으로 변환됩니다.

그렇지 않으면, 두 피연산자는 서명되지 않은 정수 유형으로 변환됩니다.

ANSI C :

그렇지 않으면, 하나의 피연산자가 서명되지 않은 int 인 경우, 다른 하나는 서명되지 않은 int로 변환됩니다.

내가 서명되지 않은 int라고 선언하지 않는 이유는 무엇입니까? 그런 다음 문제가 사라집니다.

어쨌든, i*w는 코드가 테스트하기 때문에 <= 4096으로 보장되므로 결코 오버플로가되지 않습니다.

memcpy (& buf [iW> -1? 나W <4097? 나w : 0 : 0], init, w); 나는 i의 트리플 계산을 생각하지 않는다w는 성능을 저하시킨다)

W 및/또는 h가 충분히 크고 다음 유효성 검사가 통과 될 경우 W*H가 오버플로 될 수 있습니다.

9.      if (w*h > 4096)
10.         return (NULL);

int, 부호없는 INT 혼합 작업에서 int는 서명되지 않은 int로 높아지고,이 경우 'I'의 음수 값은 큰 양수 값이됩니다. 이 경우

&buf[i*w]

바운드 값을 벗어난 값에 액세스 할 것입니다.

산술 부호 없는 것으로 수행한 모듈(또는 랩),그래서 그의 제품이 두 개의 큰 부호 정할 수 있게 보다 적은 4096.의 곱셈 int,unsigned int 에 unsigned int(섹션 참조 4.5 의 C++표준).

따라서,주어진 큰 w 고 적당한 값을에서,당신은 참으로 수으로 얻는 문제입니다.

을 확인이 정수산지 않 오버플로우 어렵습니다.하나 쉬운 방법은 변환하여 부동 소수점 및 하고 있는 부동 소수점 곱하고 보고하는 경우 그 결과 모든 합리적이다.Qwerty 제안된 긴급,사용할 수 있는 경우에 당신의 구현합니다.(그것은 일반적인 확장자에 C90 및 C++,에 존재 C99 에있을 것입니다,C++0x.)

6.3.1.8의 일반적인 산술 커버션, N1494, N1494, 6.3.1.8의 계산 (Unsigned Type1) X (서명 된 Type2)에 대한 현재 C1X 드래프트에는 3 개 단락이 있습니다.

WG 14 : C- 프로젝트 상태 및 이정표

그렇지 않으면, 서명되지 않은 정수 유형을 갖는 피연산자가 다른 피연산자 유형의 순위에 크거나 동일하다면, 서명 된 정수 유형을 가진 피연산자는 서명되지 않은 정수 유형을 가진 피연산자 유형으로 변환됩니다.

그렇지 않으면, 서명 된 정수 유형이있는 피연산자 유형이 서명되지 않은 정수 유형을 갖는 피연산자 유형의 모든 값을 나타낼 수 있다면, 서명되지 않은 정수 유형을 갖는 피연산자는 서명 된 정수 유형이있는 피연산자 유형으로 변환됩니다.

그렇지 않으면, 두 피연산자는 서명되지 않은 정수 유형으로 변환됩니다.

따라서 A가 서명되지 않은 int이고 b는 int 인 경우 (a * b)의 구문 분석은 코드 (A * (부호없는 int) b)를 생성해야합니다. b <0 또는 a * b> uint_max 인 경우 오버플로됩니다.

A가 서명되지 않은 int이고 B가 크기가 길다면 (A * B)는 ((long) a * (long) b)를 생성해야합니다. a * b> long_max 또는 a * b <long_min 인 경우 오버플로됩니다.

A가 서명되지 않은 int이고 B가 동일한 크기가 길면 (a * b)는 ((서명하지 않은) a * (부호없는 길이) b)를 생성해야합니다. b <0 또는 a * b> ulong_max 인 경우 오버플로됩니다.

"indexer"가 기대하는 유형에 대한 두 번째 질문에서, 대답은 "정수 유형"으로 나타나서 (서명 된) 정수 인덱스를 허용합니다.

6.5.2.1 배열 첨자

제약

1 표현식 중 하나는``객체 유형을 완료하기위한 포인터 ''유형이 있어야하고, 다른 표현식에는 정수 유형이 있고 결과에는 유형의 '유형'이 있습니다.

의미론

2 사후 괄호 표현식에 이어 사각형 브래킷 []의 표현식은 배열 객체의 요소의 위시 지정입니다. 첨자 연산자 []의 정의는 e1 [e2]가 (*(e1)+(e2))와 동일하다는 것입니다. 바이너리 + 연산자에게 적용되는 변환 규칙으로 인해 E1이 배열 객체 인 경우 (동일하게, 배열 객체의 초기 요소에 대한 포인터) 정수 인 E1 [E2]는 E2-th 요소를 지정합니다. E1 (0에서 계산).

포인터 표현식이 어레이 변수이고 인덱스가 음수 일 때 정적 분석을 수행하고 개발자에게 버퍼 오버런 가능성에 대해 경고하는 것은 컴파일러에 달려 있습니다. 인덱스가 양수이거나 서명되지 않은 경우에도 가능한 배열 크기 오버런에서 경고에 대해서도 마찬가지입니다.

실제로 질문에 답하기 위해, 실행중인 하드웨어를 지정하지 않고, 당신은 알지 못하며, 휴대용 코드에서 특정 행동에 의존해서는 안됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top