所以我有以下代码:
void emptyString(char* token, int size) {
for (int i=0; i < size; i++) token[i] = '\0';
}
void setDefaults(char uloginName[], char *home_directory, char *password, char *shell, char *gecos) {
emptyString(home_directory, sizeof(home_directory) - 1);
strcat(home_directory, "home/home/");
strcat(home_directory, uloginName);
}
int main(){
char buffer[256];
AccountInfo *tempAccount;
UserDB users;
char uloginName[9] = "Smith";
char homeDirectory[33];
int userID;
int groupID;
char password[17];
char shell[17];
char gecos[65];
int i, j, k;
char flag[3];
char IDString[6];
char command[11];
char blank = ' ';
setDefaults(uloginName, homeDirectory, password, shell, gecos);
return 0;
}
当我在Visual Studio中运行此代码时,我会弹出一个窗口
运行时检查失败#2 - 围绕变量'users'堆栈 损坏
这是由setDefaults()
方法中的代码行引起的。我希望有人帮助我纠正代码。我的目的是将home_directory的值设置为“ home / home / userloginname ”,其中userloginname也是传递的变量之一。
strcat()
方法。如果我使用strcpy()
作为第一个,它可以正常工作,但是一旦我想添加更多,它会向我显示一个弹出窗口,说明变量users
已损坏。以下是userDB类的代码:
class UserDB
{
private:
AccountInfo* _accounts[200]; // store up to 200 accounts
unsigned int _size; // number of account stored
unsigned int _nextUid; // next user id to be assigned
unsigned int _defaultGid; // default group id
// other private methods necessary for this class
public:
// constructors(empty), destructor
void adduser( AccountInfo* newUser);
void showUsers();
void showPasswd();
void finger(char* userLoginName);class
int size(); // return the number of accounts stored (_size)
// and other public methods (mutators/setters, accessors/getters)
};
现在,代码就像在这里一样。也许我需要制作构造函数或析构函数或诸如此类的东西,但作为一个新手,无法知道究竟是什么导致了错误并需要修复。
编辑:所以很长一段时间后我发现strcat()是导致错误的原因,但是我需要做strcat声称要做的事情。这是我的完整代码http://ideone.com/A5iWh的副本,以便有兴趣的人可以让我知道要改变什么,因为我不知道还能做什么。感谢。答案 0 :(得分:1)
emptyString(home_directory, sizeof(home_directory) - 1);
你这里有问题:
sizeof(home_directory)
此语句为您指定指针home_directory
的大小,而不是数组
如果你想在函数内部使用数组的大小,那么你必须将它作为函数参数显式传递。
此外,您的变量未初始化,导致未定义的行为
具体来说,在显示的代码段中uloginName
您需要初始化所有变量,以免它们在整个项目中引起问题。
答案 1 :(得分:1)
值得注意的问题:
// in getNextToken
while ((buffer[i] != delimeter) && (i < 256) && (j < tokenSize))
token[j++] = buffer[i++];
除了长度检查之外,没有检查您是否已到达buffer[]
内容的末尾。如果cin.getline(buffer)
读取“用户名p mypasswd”怎么办?然后:
command
填满command
但从不在结尾处放置终止空值。也许这不是问题......
uloginName
也不会插入终止空字符。
password
读取16个字节。如果密码足够短,也许你会幸运地使用null终止符。
答案 2 :(得分:0)
strcat(home_directory, uloginName);
^^^^^^^^^^ uninitialized
原因是char uloginName[9];
未在main()
内初始化,而setDefaults(...)
正在传递给uloginName
,因此 保证 nul终止字符串。
缓冲区可能超出范围,代码进入未定义的行为。
更新:从您posted in the link的代码中,它似乎一团糟。您没有像我之前所说的那样初始化字符数组。此外,我没有看到任何范围检查,因此缓冲区可能很容易超载。
例如,9
的大小只有k
,std::string
的变量值很可能超过{{1}}。这会导致堆栈溢出,并且会破坏在其附近声明的相邻变量的值。如果您对绑定检查不满意,请尝试使用{{1}}而不是裸阵列。
答案 3 :(得分:0)
您的错误消息表示&#34;堆栈溢出。&#34;你的程序堆栈中有一些固定大小的缓冲区,而且你写入的内容比缓冲区可以容纳的多。
无论何时在C或C ++中声明局部变量,都会在运行函数的堆栈中为其分配一些存储空间。让我举个例子。
#include <stdio.h>
int main()
{
short above=0;
char buffer[1];
short below=0;
strcpy(buffer, "Hello,");
strcat(buffer, " world!");
printf("%d %d %s", above, below, buffer);
}
所以我宣布buffer
有足够的空间来存储1个字节。我尝试将"Hello, world!\0"
的14个字节放入其中。我运行这个程序后会得到什么?
27762 0 Hello, world!
现在,我设置了以上&#39;显式为0。它是怎么变成27762的?好吧,这里有一个实际发生的例子:
Stack:
| .... | | ... |
| misc platform stuff | | d!\0...|
|---------------------| |--------|
| storage for 'above' | 2 bytes = sizeof(short) | rl |
|---------------------| |--------|
| padding/cookie | system dependent |ello, wo|
|---------------------| |--------|
| storage for 'buffer'| 1 byte = sizeof(buffer) -> | H |
|---------------------| |--------|
| padding/cookie | system dependent | ? ? ? |
|---------------------| |--------|
| storage for 'below' | 2 bytes = sizeof(short) | 0 0 |
| ... |
当我写入buffer
时,第一个字节落在它应该是的位置。然后接下来的几个字节开始写入&#39; padding / cookie&#39;区域。最终该区域溢出,我们继续覆盖下一个更高的东西,&#39;以上&#39;。
快速检查向我们显示27762是我的机器在世界中间解释字符rl
的方式!&#34;作为short
。
现在,像这样的错误是堆栈缓冲区溢出,或者#34;堆栈溢出&#34;。恶意用户可以利用堆栈溢出的某些实例来控制您的程序,并使其完全不同于它的设计目的。利用堆栈溢出是一种经过验证的真正的黑客技术。
以至于编译器编写者和操作系统设计者已经采取了“深度防御”的策略。防止堆栈溢出被利用。理想情况下,如果某个用户设法覆盖堆栈的坏部分,工具链会尝试做唯一合理的事情:立即崩溃。
在这种特殊情况下,编译器所做的是在存储“缓冲区”后立即插入一个特殊的难以猜测的值。称为堆栈cookie。&#39;当它离开main
时,它会检查&#39;堆栈Cookie&#39;没有改变。如果有的话,一些顽皮的东西(可能是堆栈溢出)已经发生了,所以程序会立即崩溃并显示你看到的对话框。
我们如何修复堆栈溢出?代码防守。 从不致电strcpy
,strcat
,sprintf
或他们的各个朋友。不使用固定大小的缓冲区(例如char homeDirectory[33];
),而是使用std::string homeDirectory;
等动态工具来管理字符串。如果使用得当,就不可能以覆盖意外内存的方式溢出std::string
。