-
Notifications
You must be signed in to change notification settings - Fork 3k
Closed
Labels
bugIssue is reported as a bugIssue is reported as a bugteam:VMAssigned to OTP team VMAssigned to OTP team VM
Description
Describe the bug
A non-empty 8-bit bitstring (like <<0>>
) is matched as an empty bitstring (<<>>
) when specific function clause ordering is used.
This was discovered when running property based testing on argo_varbit
.
To Reproduce
Using the following module:
-module(varbit).
-export([
write/1
]).
-spec write(undefined | bitstring()) -> binary().
write(undefined) ->
<<>>;
write(Varbit) when is_bitstring(Varbit) ->
write_internal(Varbit).
-spec write_internal(bitstring()) -> binary().
write_internal(<<Chunk:7/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 15
<<Chunk:7/bits, 0:1>>;
write_internal(<<Chunk:6/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 18
<<Chunk:6/bits, 0:2>>;
write_internal(<<Chunk:5/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 21
<<Chunk:5/bits, 0:3>>;
write_internal(<<Chunk:4/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 24
<<Chunk:4/bits, 0:4>>;
write_internal(<<Chunk:3/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 27
<<Chunk:3/bits, 0:5>>;
write_internal(<<Chunk:2/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 30
<<Chunk:2/bits, 0:6>>;
write_internal(<<Chunk:1/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 33
<<Chunk:1/bits, 0:7>>;
write_internal(<<>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 36
<<0:8>>;
write_internal(<<Chunk:7/bits, Rest/bits>>) ->
io:format("~ts:~w\n", [?FUNCTION_NAME, ?LINE]), % ?LINE = 39
<<Chunk:7/bits, 1:1, (write_internal(Rest))/bits>>.
Using an Erlang shell:
1> c(varbit).
{ok,varbit}
2> varbit:write(<<1>>).
write_internal:36
<<0>>
Expected behavior
2> varbit:write(<<0>>).
write_internal:39
write_internal:15
<<1,0>>
Affected versions
OTP 27, 28+
Additional context
Observations:
- Adding
-export([write_internal/1]).
causes the unexpected behavior to go away. - Changing the function clause ordering where
write_internal(<<>>)
appears afterwrite_internal(<<Chunk:7/bits, Rest/bits>>)
causes the unexpected behavior to go away.
Metadata
Metadata
Assignees
Labels
bugIssue is reported as a bugIssue is reported as a bugteam:VMAssigned to OTP team VMAssigned to OTP team VM