I ran into this today and after some digging found the problem...at least for my installation.
I had created my own lists in the Host/List Editor. One of them was for Gender where 'M' was the value for Male. There is also a 'M' value for Monthly in the Frequency List. The stored Procedure GetPortalRoles was written just to look for the value, not the value AND the ListName in the Join...so when it joined to the List table it was generating two rows for each role... The corrected Stored procedure is below. The "DNN_" prefix may be different in your installation, just replace it with whatever you use. I've bolded the changes I made to the proc.
ALTER PROCEDURE [dbo].[DNN_GetPortalRoles]
@PortalId int
AS
SELECT R.RoleId,
R.PortalId,
R.RoleGroupId,
R.RoleName,
R.Description,
'ServiceFee' = case when convert(int,R.ServiceFee) <> 0 then R.ServiceFee else null end,
'BillingPeriod' = case when convert(int,R.ServiceFee) <> 0 then R.BillingPeriod else null end,
'BillingFrequency' = case when convert(int,R.ServiceFee) <> 0 then L1.Text else '' end,
'TrialFee' = case when R.TrialFrequency <> 'N' then R.TrialFee else null end,
'TrialPeriod' = case when R.TrialFrequency <> 'N' then R.TrialPeriod else null end,
'TrialFrequency' = case when R.TrialFrequency <> 'N' then L2.Text else '' end,
'IsPublic' = case when R.IsPublic = 1 then 'True' else 'False' end,
'AutoAssignment' = case when R.AutoAssignment = 1 then 'True' else 'False' end,
RSVPCode,
IconFile
FROM dbo.DNN_Roles R
LEFT OUTER JOIN dbo.DNN_Lists L1 on R.BillingFrequency = L1.Value AND L1.ListName = 'Frequency'
LEFT OUTER JOIN dbo.DNN_Lists L2 on R.TrialFrequency = L2.Value AND L2.ListName = 'Frequency'
WHERE PortalId = @PortalId
OR PortalId is null
ORDER BY R.RoleName