C 代码在 64 位 Ubuntu 14.04 中工作,但在 32 位 Ubuntu 14.04 中失败
C code works in 64-bit Ubuntu 14.04 but fails in 32-bit Ubuntu 14.04
#include <stdio.h>
#include <stdlib.h>
int count = 0;
int * new_array() {
int i, *array = (int *) malloc(sizeof(int) * 9);
for(i = 0; i <= 9; i++)
array[i] = count++;
for(i = 0; i <= 9; i++)
printf("%d ", array[i]);
printf("\n");
return array;
}
int main(void) {
int i;
int *a;
for(i = 0; i < 10; i++) {
a = new_array();
}
return 0;
}
这在 64 位中工作正常,输出符合预期。
但是,在 32 位中,输出结果为:
0 1 2 3 4 5 6 7 8 9
并出现错误信息:
prog: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed.
我不明白为什么。正如我所担心的,它也应该在 64 位中失败,因为我只分配了 9 个整数大小但访问了数组的第 10 个元素。如果是这样,我为什么要关心长度?我可以给一个随机数作为长度。
由于您只为 malloc()
调用中的 9
个元素分配内存,但稍后,使用 returned 指针,您正在编写
for(i = 0; i <= 9; i++)
array[i] = count++;
实际上是 off-by-one scenario and essentially accssing memory out of bounds, creating undefined behaviour.
FWIW,UB的输出是UB,与32
或64
位架构无关。
就是说,在直接使用 returned 指针之前,始终通过测试其 return 值是否为 NULL 来检查 malloc()
是否成功。
此外,请 see why not to cast malloc()
的 return 值和 C
中的家人。
如果您在调用未定义的行为时可以确定地预期某种行为,那么它就不会是未定义的。您的问题在这里找到:
the output is as expected
除了由于您没有分配 10 个项目而导致的数组越界访问的核心问题之外,您的程序还存在以下问题:
错误
- 您永远不会释放任何内存,并且每次调用该函数都会造成内存泄漏。您还应该检查 malloc 的结果。
代码style/bad实践
避免在 C 中使用 new_array()
函数声明。这意味着 "accept anything" 作为参数。这是 C 的一个过时特性,可能会从该语言中删除。相反,将您的函数定义为 int * new_array (void)
不要使用全局变量。 count
可以在函数内部声明为局部静态变量,或者更好的是,将其作为参数传递给函数。
Casting the result of malloc is harmless but also pointless.
您可能会受益于现代 C11 编译器。看起来你还在写旧的 C90 代码。
As I'm concerned, it also should fail in 64-bit, since I only allocated 9 integer-size but accessed the 10th element of array.
这会导致未定义的行为,这可能意味着立即出现段错误或 运行 没有明显问题的完成 或 破坏您的程序状态,导致稍后发生故障,等等
这是语言无法保护您免受自身伤害的众多领域之一。
#include <stdio.h>
#include <stdlib.h>
int count = 0;
int * new_array() {
int i, *array = (int *) malloc(sizeof(int) * 9);
for(i = 0; i <= 9; i++)
array[i] = count++;
for(i = 0; i <= 9; i++)
printf("%d ", array[i]);
printf("\n");
return array;
}
int main(void) {
int i;
int *a;
for(i = 0; i < 10; i++) {
a = new_array();
}
return 0;
}
这在 64 位中工作正常,输出符合预期。
但是,在 32 位中,输出结果为: 0 1 2 3 4 5 6 7 8 9
并出现错误信息:
prog: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed.
我不明白为什么。正如我所担心的,它也应该在 64 位中失败,因为我只分配了 9 个整数大小但访问了数组的第 10 个元素。如果是这样,我为什么要关心长度?我可以给一个随机数作为长度。
由于您只为 malloc()
调用中的 9
个元素分配内存,但稍后,使用 returned 指针,您正在编写
for(i = 0; i <= 9; i++)
array[i] = count++;
实际上是 off-by-one scenario and essentially accssing memory out of bounds, creating undefined behaviour.
FWIW,UB的输出是UB,与32
或64
位架构无关。
就是说,在直接使用 returned 指针之前,始终通过测试其 return 值是否为 NULL 来检查 malloc()
是否成功。
此外,请 see why not to cast malloc()
的 return 值和 C
中的家人。
如果您在调用未定义的行为时可以确定地预期某种行为,那么它就不会是未定义的。您的问题在这里找到:
the output is as expected
除了由于您没有分配 10 个项目而导致的数组越界访问的核心问题之外,您的程序还存在以下问题:
错误
- 您永远不会释放任何内存,并且每次调用该函数都会造成内存泄漏。您还应该检查 malloc 的结果。
代码style/bad实践
避免在 C 中使用
new_array()
函数声明。这意味着 "accept anything" 作为参数。这是 C 的一个过时特性,可能会从该语言中删除。相反,将您的函数定义为int * new_array (void)
不要使用全局变量。
count
可以在函数内部声明为局部静态变量,或者更好的是,将其作为参数传递给函数。Casting the result of malloc is harmless but also pointless.
您可能会受益于现代 C11 编译器。看起来你还在写旧的 C90 代码。
As I'm concerned, it also should fail in 64-bit, since I only allocated 9 integer-size but accessed the 10th element of array.
这会导致未定义的行为,这可能意味着立即出现段错误或 运行 没有明显问题的完成 或 破坏您的程序状态,导致稍后发生故障,等等
这是语言无法保护您免受自身伤害的众多领域之一。