Reputation: 33
GCC return no errors or warnings. The program segfaults after entering a password over 21 characters. At first I had:
hash_p = SuperFastHash(query.pwd, strlen(query.pwd));
get this warning from GCC:
warning: assignment makes pointer from integer without a cast [-Wint- conversion]
hash_p = SuperFastHash(query.pwd, strlen(query.pwd));
^
so I changed it to:
sprintf(hash_p, "%d", SuperFastHash(query.pwd, strlen(query.pwd)));
because the hash function returns an int. strcmp compares two type const char *.
When I debug the program using gdb, it returns this:
Program received signal SIGSEGV, Segmentation fault.
0xb7e500d5 in _IO_vfprintf_internal (s=<optimized out>, format=<optimized out>,
ap=0xbffff46c "\261\a@") at vfprintf.c:1636
1636 vfprintf.c: No such file or directory.
Program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdint.h>
#define BUF_SIZE 1024
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
uint32_t SuperFastHash (const char * data, int len) {
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL) return 0;
rem = len & 3;
len >>= 2;
for (;len > 0; len--) {
hash += get16bits (data);
tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*sizeof (uint16_t);
hash += hash >> 11;
}
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += (signed char)*data;
hash ^= hash << 10;
hash += hash >> 1;
}
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
struct log_n {
char uid[BUF_SIZE];
char pwd[BUF_SIZE];
};
struct log_n acc[1] = {
"username","-1257730142"
};
struct log_n query;
int main() {
char *hash_p;
do {
do{
printf("Username: ");
fgets(query.uid, sizeof query.uid, stdin);
query.uid[strcspn(query.uid, "\n")] = '\0';
if (strlen(query.uid) < 4) {
printf("Username must be between four and eight characters.\nTry again.\n");
}
if (strlen(query.uid) > 8) {
printf("Username must be less than eight characters.\nTry again.\n");
}
} while (strlen(query.uid) < 4 || strlen(query.uid) > 8);
do{
printf("Password: ");
fgets(query.pwd, sizeof query.pwd, stdin);
query.pwd[strcspn(query.pwd, "\n")] = '\0';
sprintf(hash_p, "%d", SuperFastHash(query.pwd, strlen(query.pwd)));
if (strlen(query.pwd) < 21) {
printf("Password must be atleast twenty-one characters long.\nTry again.\n");
}
} while (strlen(query.pwd) < 21);
} while (strcmp(query.uid, acc->uid) !=0 || strcmp(hash_p, acc->pwd) !=0);
}
Note: this is not a homework assignment. I am just a person learning C with help of people using the internet.
Upvotes: 3
Views: 10522
Reputation: 6989
SuperFastHash()
explicitly returns an unsigned 32-bit integer (uint32_t
). Why are you printing that to a string and comparing / storing strings?
It would make more sense to just store and compare the numeric values.
You are currently confusing the pwd
field of your struct:
acc[0].pwd
stores a hashquery.pwd
stores the plaintext passwordIf for some reason, you do want to store the number as a string (perhaps in a file), then please do it correctly!
An unsigned value will never be negative (your struct initialization specifies -1257730142).
char input_pwd[] = "my password";
uint32_t input_hash;
char hash_str[11]; /* 32-bit unsigned int can't be more than 10 characters, +1 for nul */
input_hash = SuperFastHash(input_pwd, strlen(input_pwd));
snprintf(hash_str, sizeof(hash_str), "%" PRIu32, input_hash);
In most cases you could get away with "%u"
as the format string, but "%" PRIu32
is safer / more correct.
As pointed out below by gcc
, your struct initialization is incorrect, and currently works "by mistake".
Did you mean this:
struct log_n acc[1] = {
{ "username", "3037237154" }
};
or this:
struct log_n acc = {
"username", "3037237154"
};
Additionally, gcc
will point you at your mistake if you compile with -Wall
(to enable all warnings) - a very good habit to get into:
'hash_p' is used uninitialized in this function
$ gcc main.c -o main -Wall
main.c:72:23: warning: missing braces around initializer [-Wmissing-braces]
struct log_n acc[1] = {
^
main.c:72:23: note: (near initialization for 'acc')
main.c: In function 'main':
main.c:99:21: warning: 'hash_p' is used uninitialized in this function [-Wuninitialized]
sprintf(hash_p, "%d", SuperFastHash(query.pwd, strlen(query.pwd)));
^
Finally, the vfprintf.c: No such file or directory
message is informing you that GDB can't find the sources for printf()
, which in this case is unrelated to your problem.
If you are going to be using GDB, then it's always a good idea to compile with -g
to include the debug information in your binary.
Upvotes: 0
Reputation: 50911
In this line:
sprintf(hash_p, "%d", SuperFastHash(query.pwd, strlen(query.pwd)));
hash_p
has never been initialized. It points nowhere.
Just replace char *hash_p;
by char hash_p[20]
. I'm not sure what the maximum length of the hash is (I assumed 20), so maybe 20
should be replaced by a more appropriate value.
Upvotes: 3