DiceDB / dice

DiceDB is a redis-compliant, reactive, scalable, highly-available, unified cache optimized for modern hardware.
https://dicedb.io/
Other
6.88k stars 1.1k forks source link

Inconsistent `SETBIT`: Handling negative and large offset values #1114

Closed Yashasv-Prajapati closed 1 week ago

Yashasv-Prajapati commented 1 month ago

Steps to reproduce

  1. Start the dicedb server and connect to it through whatever client(redis-cli or something else) you prefer.
  2. Run either of the following commands a. SETBIT <key> -1 1 without setting the <key> to any value. b. Set a value corresponding to a key, and then run SETBIT <key> <large_negative_number> 1. Make sure the abs(<large_negative_number>) is greater than the bit length of the value corresponding to the key.
  3. Both will crash the dicedb server, and will close the connection.

Expected output

This should throw an out of range error for negative offsets.

(error) ERR bit offset is not an integer or out of range

Observed output

The observed output when the above set of commands when run on DiceDB

Same for both the cases.

Error: Server closed the connection

Expectations for resolution

This issue will be considered resolved when the following things are done

  1. Changes in the dice code to meet the expected behavior
  2. Addition of relevant test case to ensure we catch the regression

You can find the tests under the integration_tests directory of the dice repository and the steps to run are in the README file. Refer to the following links to set up DiceDB and Redis 7.2.5 locally

Follow up

Once these changes are done, drop a comment in the issue #813 regarding the closing of this issue.

Yashasv-Prajapati commented 1 month ago

@apoorvyadav1111 could you please assign this to me

apoorvyadav1111 commented 1 month ago

Assigned, @Yashasv-Prajapati . Thanks for finding the bug and taking this up.

mayank2424 commented 1 month ago

Steps to reproduce

  1. Start the dicedb server and connect to it through whatever client(redis-cli or something else) you prefer.
  2. Run either of the following commands a. SETBIT <key> -1 1 without setting the <key> to any value. b. Set a value corresponding to a key, and then run SETBIT <key> <large_negative_number> 1. Make sure the abs(<large_negative_number>) is greater than the bit length of the value corresponding to the key.
  3. Both will crash the dicedb server, and will close the connection.

Expected output

This should throw an out of range error for negative offsets.

(error) ERR bit offset is not an integer or out of range

Observed output

The observed output when the above set of commands when run on DiceDB

Same for both the cases.

Error: Server closed the connection

Expectations for resolution

This issue will be considered resolved when the following things are done

  1. Changes in the dice code to meet the expected behavior
  2. Addition of relevant test case to ensure we catch the regression

You can find the tests under the integration_tests directory of the dice repository and the steps to run are in the README file. Refer to the following links to set up DiceDB and Redis 7.2.5 locally

Follow up

Once these changes are done, drop a comment in the issue #813 regarding the closing of this issue.

@apoorvyadav1111 @arpitbbhayani I looked into the issue and found that the following code in evalSETBIT is causing the server disconnection error.

Line 1216 in eval.go:

offset, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
     return diceerrors.NewErrWithMessage("bit offset is not an integer or out of range")
}

The issue occurs because strconv.ParseInt allows negative numbers like -1. This is due to how signed 64-bit integers work which support both negative and positive values. The valid range for a signed 64-bit integer is from -2^63 to 2^63-1 and because of this strconv.ParseInt correctly handles negative numbers as valid base-10 integers and values like -1 is considered valid which leads to err as nil. When offset is set to -1 the following code throws an "index out of range" error as expected because it's trying to access byteArray at index -1.

Line 1261 in eval.go:

resp := byteArray.GetBit(int(offset))
byteArray.SetBit(int(offset), value)

Let me know if I’ve understood this correctly.

arpitbbhayani commented 1 month ago

Hello @Yashasv-Prajapati,

There has been no activity on this issue for the past 5 days. It would be awesome if you keep posting updates to this issue so that we know you are actively working on it.

We are really eager to close this issue at the earliest, hence if we continue to see the inactivity, we will have to reassign the issue to someone else. We are doing this to ensure that the project maintains its momentum and others are not blocked on this work.

Just drop a comment with the current status of the work or share any issues you are facing. We can always chip in to help you out.

Thanks again.