Search code examples
clinuxembedded-databasegdbm

Unable to retrive data from GDBM databas from differnt function in c


hi there i am trying to develop 3 tier server with embedded database.

my issue is that i am able to save data in gdbm database but when i try to retrieve data from other functions it always returns null value. i have also point out the issue which is the null termination (verified through gdb output) of key value while i am saving data key does not ends with \0 but while retrieving data it is terminated by \0 i am not quite sure about this theory and don't know how to solve it.

things that i have tried:

  • tried to add null character manually but did not worked
  • tired to remove null character from key but it still does not work.
  • tried to get key from same structure hoping that issue may be due to different format but did not worked
  • tried to replace null character but did not helped because i don't know what i am doing wrong and why at the time of saving data there is no null character.

i have attached minimum code to reproduce same error hope so someone will point out my mistake in the mean time i will still try to resolve this issue but your guideline can be helpful.

source Code

#include <gdbm.h>
#include <string.h>
#include <stdio.h>

#define STR_SIZE 20
#define BUFFER_SIZE 256
typedef struct UserData
{
    char name[STR_SIZE];
    char accountNumber[STR_SIZE];
    char password[STR_SIZE];
    long balence;
} userData;

void simulateSelect(GDBM_FILE dbFile);
void simulateInsert(GDBM_FILE dbFile);

int main(int argc, char **argv)
{
    GDBM_FILE dbFile = gdbm_open("newSampleDB", 0, GDBM_WRCREAT | GDBM_READER, 0660, 0);
    simulateInsert(dbFile);
    simulateSelect(dbFile);
    return 0;
}

void simulateInsert(GDBM_FILE dbFile)
{
    //RPC call data sent to server [function mode [data for function call]
    char *request = "signup user fawad 10120 11223 120";

    //server receiving end
    char buffer[BUFFER_SIZE];
    char name[STR_SIZE];
    char id[STR_SIZE];
    char pass[STR_SIZE];
    char bal[STR_SIZE];
    char temp[STR_SIZE];
    char mode[STR_SIZE];
    //parse cliet request and slect one of the avaiable opertaion
    sscanf(request, "%s %s %s %s %s %s", temp, mode, name, id, pass, bal);
    bzero(buffer, BUFFER_SIZE);
    //forward request to database server
    sprintf(buffer, "insert %s %s %s %s %s", mode, name, id, pass, bal);
    // databse server receiving end
    userData data;
    bzero(name, STR_SIZE);
    bzero(id, STR_SIZE);
    bzero(pass, STR_SIZE);
    //parse request and take actoin
    sscanf(buffer, "%s %s %s %s %s %li", temp, temp, name, id, pass, &data.balence);
    strcpy(data.name, name);
    strcpy(data.accountNumber, id);
    strcpy(data.password, pass);
    //save data in database
    datum key;
    // i have checked through gdb at this point key.dptr does not have null termination i.e. \0
    // key.dptr = 10120
    key.dptr = data.accountNumber;
    key.dsize = STR_SIZE + 1;
    datum _data;
    _data.dptr = (char *)&data;
    _data.dsize = sizeof(data);
    int res = gdbm_store(dbFile, key, _data, GDBM_INSERT);
    printf("Indert Status = %d", res);
    //works fine here and data is retrived
    datum data3 = gdbm_fetch(dbFile, key);
    userData *data1 = (userData *)(data3.dptr);
    sprintf(buffer, "1 %s %s %s %li", data1->name, data1->accountNumber, data1->password, data1->balence);
    fprintf(stdout, "%s", buffer);
}

void simulateSelect(GDBM_FILE dbFile)
{
    //client again initiates request to login
    char *request = "login user 10120 11223";
    //server end
    char buffer[BUFFER_SIZE];
    char id[STR_SIZE];
    char pass[STR_SIZE];
    char temp[STR_SIZE];
    char mode[STR_SIZE];
    bzero(buffer, BUFFER_SIZE);
    //parse request and select operatoin
    sscanf(request, "%s %s %s %s", temp, mode, id, pass);
    //send request to database server
    sprintf(buffer, "select %s %s", mode, id);
    //databse server end
    bzero(id, STR_SIZE);
    //parse request
    sscanf(buffer, "%s %s %s", temp, mode, id);
    // userData d;
    // strcpy(d.accountNumber, id);
    datum _data;
    datum key;
    // at this point key.dptr have null termiantion i.e key.dptr= 10120\0
    key.dptr = id;
    // key.dptr = d.accountNumber;
    key.dsize = STR_SIZE + 1;
    _data = gdbm_fetch(dbFile, key);
    userData *data = (userData *)(_data.dptr);
    // ((userData *)res.dptr)->name)
    sprintf(buffer, "1 %s %s %s %li", data->name, data->accountNumber, data->password, data->balence);
    fprintf(stdout, "%s", buffer);
}

Solution

  • The problem is very likely that you use the whole (and more!) of the accountNumber array as key, even the parts beyond the string null-terminator which will be uninitialized and have indeterminate values.

    The key you use when you write will thus likely not be exactly the same as the one you use when reading the data.

    The solution is to make sure that all of the accountNumber array will be initialized (as in memset(data.accountNumber, 0, sizeof data.accountNumber)) before copying the string to it.


    The problem with e.g.

    bzero(id, STR_SIZE);
    // ...
    strcpy(data.accountNumber, id);
    

    is that strcpy will not copy data beyond the string null-terminator, so it doesn't copy the full array id, only a small part of it. Which will leave the remaining elements of data.accountNumber uninitialized.

    You must initialize data.accountNumber itself.